This is the mail archive of the java-patches@sourceware.cygnus.com mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch: IA-64 support for libffi


I'm checking in the appended patch.  This adds IA-64 support to
libffi.  This is the first step in porting libgcj to the IA-64.  Many
thanks to Hans Boehm for this work.

2000-02-25  Hans Boehm <boehm@acm.org>

	* src/ia64/ffi.c, src/ia64/ia64_flags.h, src/ia64/unix.S: New
	files.
	* src/raw_api.c (ffi_translate_args): Fixed typo in argument
	list.
	(ffi_prep_raw_closure): Use ffi_translate_args, not
	ffi_closure_translate.
	* src/java_raw_api.c: New file.
	* src/ffitest.c (closure_test_fn): New function.
	(main): Define `rint' as long long on IA64.  Added new test when
	FFI_CLOSURES is defined.
	* include/ffi.h.in (ALIGN): Use size_t, not unsigned.
	(ffi_abi): Recognize IA64.
	(ffi_raw): Added `flt' field.
	Added "Java raw API" code.
	* configure.in: Recognize ia64.
	* Makefile.am (TARGET_SRC_IA64): New macro.
	(libffi_la_common_SOURCES): Added java_raw_api.c.
	(libffi_la_SOURCES): Define in IA64 case.

Tom

Index: Makefile.am
===================================================================
RCS file: /cvs/java/libgcj/libffi/Makefile.am,v
retrieving revision 1.4
diff -u -r1.4 Makefile.am
--- Makefile.am	1999/12/31 22:44:09	1.4
+++ Makefile.am	2000/02/25 19:02:23
@@ -42,13 +42,15 @@
 TARGET_SRC_X86 = src/x86/ffi.c src/x86/sysv.S
 TARGET_SRC_SPARC = src/sparc/ffi.c src/sparc/v8.S
 TARGET_SRC_ALPHA = src/alpha/ffi.c src/alpha/osf.S
+TARGET_SRC_IA64 = src/alpha/ffi.c src/alpha/unix.S
 TARGET_SRC_M68K = src/m68k/ffi.c src/m68k/sysv.S
 TARGET_SRC_POWERPC = src/powerpc/ffi.c src/powerpc/sysv.S
 TARGET_SRC_ARM =  src/arm/sysv.S src/arm/ffi.c
 
 ##libffi_la_SOURCES = src/debug.c src/prep_cif.c src/types.c $(TARGET_SRC_@TARGET@)
 ## Work around automake deficiency
-libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c src/raw_api.c 
+libffi_la_common_SOURCES = src/debug.c src/prep_cif.c src/types.c \
+		src/raw_api.c src/java_raw_api.c
 if MIPS_GCC
 libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_MIPS_GCC)
 endif
@@ -63,6 +65,9 @@
 endif
 if ALPHA
 libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_ALPHA)
+endif
+if IA64
+libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_IA64)
 endif
 if M68K
 libffi_la_SOURCES = $(libffi_la_common_SOURCES) $(TARGET_SRC_M68K)
Index: configure.in
===================================================================
RCS file: /cvs/java/libgcj/libffi/configure.in,v
retrieving revision 1.3
diff -u -r1.3 configure.in
--- configure.in	1999/09/01 23:16:34	1.3
+++ configure.in	2000/02/25 19:02:23
@@ -27,6 +27,7 @@
 sparc-sun-4*) TARGET=SPARC; TARGETDIR=sparc;;
 sparc-sun-*) TARGET=SPARC; TARGETDIR=sparc;;
 alpha*-*-linux* | alpha*-*-osf*) TARGET=ALPHA; TARGETDIR=alpha;;
+ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;;
 m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;;
 powerpc-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;;
 powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;;
@@ -42,6 +43,7 @@
 AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC)
 AM_CONDITIONAL(X86, test x$TARGET = xX86)
 AM_CONDITIONAL(ALPHA, test x$TARGET = xALPHA)
+AM_CONDITIONAL(IA64, test x$TARGET = xIA64)
 AM_CONDITIONAL(M68K, test x$TARGET = xM68K)
 AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
 AM_CONDITIONAL(ARM, test x$TARGET = xARM)
Index: include/ffi.h.in
===================================================================
RCS file: /cvs/java/libgcj/libffi/include/ffi.h.in,v
retrieving revision 1.3
diff -u -r1.3 ffi.h.in
--- ffi.h.in	1999/09/01 23:16:34	1.3
+++ ffi.h.in	2000/02/25 19:02:24
@@ -24,6 +24,32 @@
 
    ----------------------------------------------------------------------- */
 
+/* -------------------------------------------------------------------
+   The basic API is described in the README file.
+
+   The raw API is designed to bypass some of the argument packing
+   and unpacking on architectures for which it can be avoided.
+
+   The closure API allows interpreted functions to be packaged up
+   inside a C function pointer, so that they can be called as C functions,
+   with no understanding on the client side that they are interpreted.
+   It can also be used in other cases in which it is necessary to package
+   up a user specified parameter and a function pointer as a single
+   function pointer.
+
+   The closure API must be implemented in order to get its functionality,
+   e.g. for use by gij.  Routines are provided to emulate the raw API
+   if the underlying platform doesn't allow faster implementation.
+
+   More details on the raw and cloure API can be found in:
+
+   http://sourceware.cygnus.com/ml/java-discuss/1999-q3/msg00138.html
+
+   and
+
+   http://sourceware.cygnus.com/ml/java-discuss/1999-q3/msg00174.html
+   -------------------------------------------------------------------- */
+
 #ifndef LIBFFI_H
 #define LIBFFI_H
 
@@ -138,7 +164,9 @@
 
 /* ---- Generic type definitions ----------------------------------------- */
 
-#define ALIGN(v, a)  (((((unsigned) (v))-1) | ((a)-1))+1)
+#define ALIGN(v, a)  (((((size_t) (v))-1) | ((a)-1))+1)
+/* The closure code assumes that this works on pointers, i.e. a size_t	*/
+/* can hold a pointer.							*/
 
 typedef enum ffi_abi {
 
@@ -159,6 +187,12 @@
   FFI_DEFAULT_ABI = FFI_SYSV,
 #endif
 
+  /* ---- Intel ia64 ---------------- */
+#ifdef IA64
+  FFI_UNIX,   	/* Linux and all Unix variants use the same conventions	*/
+  FFI_DEFAULT_ABI = FFI_UNIX,
+#endif
+
   /* ---- Mips --------------------- */
 #ifdef MIPS
   FFI_O32,
@@ -268,6 +302,7 @@
 typedef union {
   SINT_ARG sint;
   UINT_ARG uint;
+  float	   flt;
   char     data[SIZEOF_ARG];
   void*    ptr;
 } ffi_raw;
@@ -281,8 +316,22 @@
 void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
 size_t ffi_raw_size (ffi_cif *cif);
 
+#if !NO_JAVA_RAW_API
 
+/* This is analogous to the raw API, except it uses Java parameter	*/
+/* packing, even on 64-bit machines.  I.e. on 64-bit machines		*/
+/* longs and doubles are followed by an empty 64-bit word.		*/
+
+void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, 
+		        void (*fn)(), 
+		        /*@out@*/ void *rvalue, 
+		        /*@dependent@*/ ffi_raw *avalue);
+
+void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
+void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
+size_t ffi_java_raw_size (ffi_cif *cif);
 
+#endif /* !NO_JAVA_RAW_API */
 
 #endif /* !FFI_NO_RAW_API */
 
@@ -294,6 +343,21 @@
 #define FFI_TRAMPOLINE_SIZE 10
 #define FFI_NATIVE_RAW_API 1	/* and has native raw api support */
 
+#elif defined(IA64)
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24  /* Really the following struct, which 	*/
+				/* can be interpreted as a C function	*/
+				/* decriptor:				*/
+
+struct ffi_ia64_trampoline_struct {
+    void * code_pointer;	/* Pointer to ffi_closure_UNIX	*/
+    void * fake_gp;		/* Pointer to closure, installed as gp	*/
+    void * real_gp;		/* Real gp value, reinstalled by 	*/
+				/* ffi_closure_UNIX.			*/
+};
+#define FFI_NATIVE_RAW_API 0
+
 #else 
 
 #define FFI_CLOSURES 0
@@ -346,6 +410,14 @@
 		      ffi_cif *cif,
 		      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
 		      void *user_data);
+
+#ifndef NO_JAVA_RAW_API
+ffi_status
+ffi_prep_java_raw_closure (ffi_raw_closure*,
+		           ffi_cif *cif,
+		           void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+		           void *user_data);
+#endif
 
 #endif /* !FFI_NO_RAW_API */
 #endif /* FFI_CLOSURES */
Index: src/ffitest.c
===================================================================
RCS file: /cvs/java/libgcj/libffi/src/ffitest.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 ffitest.c
--- ffitest.c	1999/08/08 13:27:19	1.1.1.1
+++ ffitest.c	2000/02/25 19:02:25
@@ -196,6 +196,16 @@
   return ts1;
 }
 
+/* Take an int and a float argument, together with int userdata, and 	*/
+/* return the sum.							*/
+static void closure_test_fn(ffi_cif* cif,void* resp,void** args, void* userdata)
+{
+    *(int*)resp =
+	 *(int *)args[0] + (int)(*(float *)args[1]) + (int)(long)userdata;
+}
+
+typedef int (*closure_test_type)(int, float);
+
 int main(/*@unused@*/ int argc, /*@unused@*/ char *argv[])
 {
   ffi_cif cif;
@@ -214,7 +224,7 @@
   signed int si1;
   signed int si2;
 
-#if defined(ALPHA) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
+#if defined(ALPHA) || defined(IA64) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
   long long rint;
 #else
   int rint;
@@ -690,6 +700,27 @@
 
     free (ts5_result);
   }
+
+# if FFI_CLOSURES
+  /* A simple closure test */
+    {
+      ffi_closure cl;
+      ffi_type * cl_arg_types[3];
+
+      cl_arg_types[0] = &ffi_type_sint;
+      cl_arg_types[1] = &ffi_type_float;
+      cl_arg_types[2] = NULL;
+      
+      /* Initialize the cif */
+      CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, 
+	    	         &ffi_type_sint, cl_arg_types) == FFI_OK);
+
+      CHECK(ffi_prep_closure(&cl, &cif, closure_test_fn,
+			     (void *) 3 /* userdata */)
+	    == FFI_OK);
+      CHECK((*((closure_test_type)(&cl)))(1, 2.0) == 6);
+    }
+# endif
 
   /* If we arrived here, all is good */
   (void) puts("\nLooks good. No surprises.\n");
Index: src/java_raw_api.c
===================================================================
RCS file: java_raw_api.c
diff -N java_raw_api.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ java_raw_api.c	Fri Feb 25 11:02:26 2000
@@ -0,0 +1,271 @@
+/* -----------------------------------------------------------------------
+   java_raw_api.c - Copyright (c) 1999  Cygnus Solutions
+
+   Cloned from raw_api.c
+
+   Raw_api.c author: Kresten Krab Thorup <krab@gnu.org>
+   Java_raw_api.c author: Hans-J. Boehm <hboehm@hpl.hp.com>
+
+   $Id $
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+/* This defines a Java- and 64-bit specific variant of the raw API.	*/
+/* It assumes that "raw" argument blocks look like Java stacks on a 	*/
+/* 64-bit machine.  Arguments that can be stored in a single stack	*/
+/* stack slots (longs, doubles) occupy 128 bits, but only the first	*/
+/* 64 bits are actually used.  						*/
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#if !defined(NO_JAVA_RAW_API) && !defined(FFI_NO_RAW_API)
+
+size_t
+ffi_java_raw_size (ffi_cif *cif)
+{
+  size_t result = 0;
+  int i;
+
+  ffi_type **at = cif->arg_types;
+
+  for (i = cif->nargs-1; i >= 0; i--, at++)
+    {
+      switch((*at) -> type) {
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_SINT64:
+	  result += 2 * SIZEOF_ARG;
+	  break;
+	case FFI_TYPE_STRUCT:
+	  /* No structure parameters in Java.	*/
+	  abort();
+	default:
+	  result += SIZEOF_ARG;
+      }
+    }
+
+  return result;
+}
+
+
+void
+ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
+{
+  unsigned i;
+  ffi_type **tp = cif->arg_types;
+
+#if WORDS_BIGENDIAN
+
+  for (i = 0; i < cif->nargs; i++, tp++, args++)
+    {	  
+      switch ((*tp)->type)
+	{
+	case FFI_TYPE_UINT8:
+	case FFI_TYPE_SINT8:
+	  *args = (void*) ((char*)(raw++) + SIZEOF_ARG - 1);
+	  break;
+	  
+	case FFI_TYPE_UINT16:
+	case FFI_TYPE_SINT16:
+	  *args = (void*) ((char*)(raw++) + SIZEOF_ARG - 2);
+	  break;
+
+#if SIZEOF_ARG >= 4	  
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_SINT32:
+	  *args = (void*) ((char*)(raw++) + SIZEOF_ARG - 4);
+	  break;
+#endif
+	
+#if SIZEOF_ARG == 8	  
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_DOUBLE:
+	  *args = (void *)raw;
+	  raw += 2;
+	  break;
+#endif
+
+	case FFI_TYPE_POINTER:
+	  *args = (void*) &(raw++)->ptr;
+	  break;
+	  
+	default:
+	  *args = raw;
+	  raw += ALIGN ((*tp)->size, SIZEOF_ARG) / SIZEOF_ARG;
+	}
+    }
+
+#else /* WORDS_BIGENDIAN */
+
+#if !PDP
+
+  /* then assume little endian */
+  for (i = 0; i < cif->nargs; i++, tp++, args++)
+    {
+#if SIZEOF_ARG == 8
+      switch((*tp)->type) {
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_DOUBLE:
+	  *args = (void*) raw;
+	  raw += 2;
+	  break;
+	default:
+	  *args = (void*) raw++;
+      }
+#else /* SIZEOF_ARG != 8 */
+	*args = (void*) raw;
+	raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
+#endif /* SIZEOF_ARG == 8 */
+    }
+
+#else
+#error "pdp endian not supported"
+#endif /* ! PDP */
+
+#endif /* WORDS_BIGENDIAN */
+}
+
+void
+ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
+{
+  unsigned i;
+  ffi_type **tp = cif->arg_types;
+
+  for (i = 0; i < cif->nargs; i++, tp++, args++)
+    {	  
+      switch ((*tp)->type)
+	{
+	case FFI_TYPE_UINT8:
+	  (raw++)->uint = *(UINT8*) (*args);
+	  break;
+
+	case FFI_TYPE_SINT8:
+	  (raw++)->sint = *(SINT8*) (*args);
+	  break;
+
+	case FFI_TYPE_UINT16:
+	  (raw++)->uint = *(UINT16*) (*args);
+	  break;
+
+	case FFI_TYPE_SINT16:
+	  (raw++)->sint = *(SINT16*) (*args);
+	  break;
+
+#if SIZEOF_ARG >= 4
+	case FFI_TYPE_UINT32:
+	  (raw++)->uint = *(UINT32*) (*args);
+	  break;
+
+	case FFI_TYPE_SINT32:
+	  (raw++)->sint = *(SINT32*) (*args);
+	  break;
+#endif
+        case FFI_TYPE_FLOAT:
+	  (raw++)->flt = *(FLOAT32*) (*args);
+	  break;
+
+#if SIZEOF_ARG == 8
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_DOUBLE:
+	  raw->uint = *(UINT64*) (*args);
+	  raw += 2;
+	  break;
+#endif
+
+	case FFI_TYPE_POINTER:
+	  (raw++)->ptr = **(void***) args;
+	  break;
+
+	default:
+#if SIZEOF_ARG == 8
+	  FFI_ASSERT(FALSE);	/* Should have covered all cases */
+#else	
+	  memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
+	  raw += ALIGN ((*tp)->size, SIZEOF_ARG) / SIZEOF_ARG;
+#endif
+	}
+    }
+}
+
+#if !FFI_NATIVE_RAW_API
+
+
+/* This is a generic definition of ffi_raw_call, to be used if the
+ * native system does not provide a machine-specific implementation.
+ * Having this, allows code to be written for the raw API, without
+ * the need for system-specific code to handle input in that format;
+ * these following couple of functions will handle the translation forth
+ * and back automatically. */
+
+void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, 
+		   void (*fn)(), 
+		   /*@out@*/ void *rvalue, 
+		   /*@dependent@*/ ffi_raw *raw)
+{
+  void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
+  ffi_java_raw_to_ptrarray (cif, raw, avalue);
+  ffi_call (cif, fn, rvalue, avalue);
+}
+
+#if FFI_CLOSURES		/* base system provides closures */
+
+static void 
+ffi_java_translate_args (ffi_cif *cif, void *rvalue,
+		    void **avalue, void *user_data)
+{
+  ffi_raw *raw = (ffi_raw*)alloca (ffi_java_raw_size (cif));
+  ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
+
+  ffi_java_ptrarray_to_raw (cif, avalue, raw);
+  (*cl->fun) (cif, rvalue, raw, cl->user_data);
+}
+
+/* Again, here is the generic version of ffi_prep_raw_closure, which
+ * will install an intermediate "hub" for translation of arguments from
+ * the pointer-array format, to the raw format */
+
+ffi_status
+ffi_prep_java_raw_closure (ffi_raw_closure* cl,
+		      ffi_cif *cif,
+		      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+		      void *user_data)
+{
+  ffi_status status;
+
+  status = ffi_prep_closure ((ffi_closure*) cl, 
+			     cif,
+			     &ffi_java_translate_args,
+			     (void*)cl);
+  if (status == FFI_OK)
+    {
+      cl->fun       = fun;
+      cl->user_data = user_data;
+    }
+
+  return status;
+}
+
+#endif /* FFI_CLOSURES */
+#endif /* !FFI_NATIVE_RAW_API */
+#endif /* !FFI_NO_RAW_API */
Index: src/raw_api.c
===================================================================
RCS file: /cvs/java/libgcj/libffi/src/raw_api.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 raw_api.c
--- raw_api.c	1999/08/08 13:27:19	1.1.1.1
+++ raw_api.c	2000/02/25 19:02:26
@@ -202,13 +202,13 @@
 #if FFI_CLOSURES		/* base system provides closures */
 
 static void 
-ffi_translate_args (ffi_cif *cif, void *ravlue,
+ffi_translate_args (ffi_cif *cif, void *rvalue,
 		    void **avalue, void *user_data)
 {
   ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
-  ffi_ptrarray_to_raw (cif, avalue, raw);
-
   ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
+
+  ffi_ptrarray_to_raw (cif, avalue, raw);
   (*cl->fun) (cif, rvalue, raw, cl->user_data);
 }
 
@@ -226,7 +226,7 @@
 
   status = ffi_prep_closure ((ffi_closure*) cl, 
 			     cif,
-			     &ffi_closure_translate,
+			     &ffi_translate_args,
 			     (void*)cl);
   if (status == FFI_OK)
     {
Index: src/ia64/ffi.c
===================================================================
RCS file: ffi.c
diff -N ffi.c
--- /dev/null	Tue May  5 13:32:27 1998
+++ ffi.c	Fri Feb 25 11:02:28 2000
@@ -0,0 +1,670 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 1998 Cygnus Solutions
+	   Copyright (c) 2000 Hewlett Packard Company
+   
+   IA64 Foreign Function Interface 
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+#include "ia64_flags.h"
+
+/* Memory image of fp register contents.  Should eventually be an fp 	*/
+/* type long enough to hold an entire register.  For now we use double.	*/
+typedef double float80;
+
+/* The stack layout at call to ffi_prep_regs.  Other_args will remain	*/
+/* on the stack for the actual call.  Everything else we be transferred	*/
+/* to registers and popped by the assembly code.			*/
+
+struct ia64_args {
+    long scratch[2];	/* Two scratch words at top of stack.		*/
+			/* Allows sp to passed as arg pointer.		*/
+    void * r8_contents;	/* Value to be passed in r8			*/
+    long spare;		/* Not used.					*/
+    float80 fp_regs[8]; /* Contents of 8 floating point argument 	*/
+			/* registers.					*/
+    long out_regs[8];	/* Contents of the 8 out registers used 	*/
+			/* for integer parameters.			*/
+    long other_args[0]; /* Arguments passed on stack, variable size	*/
+			/* Treated as continuation of out_regs.		*/
+};
+
+static size_t float_type_size(unsigned short tp)
+{
+  switch(tp) {
+    case FFI_TYPE_FLOAT:
+      return sizeof(float);
+    case FFI_TYPE_DOUBLE:
+      return sizeof(double);
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+    case FFI_TYPE_LONGDOUBLE:
+      return sizeof(long double);
+#endif
+    default:
+      FFI_ASSERT(0);
+  }
+}
+
+/*
+ * Is type a struct containing at most n floats, doubles, or extended
+ * doubles, all of the same fp type?
+ * If so, set *element_type to the fp type.
+ */
+static bool is_homogeneous_fp_aggregate(ffi_type * type, int n,
+				        unsigned short * element_type)
+{
+  ffi_type **ptr; 
+  unsigned short element, struct_element;
+
+  int type_set = 0;
+
+  FFI_ASSERT(type != NULL);
+
+  FFI_ASSERT(type->elements != NULL);
+
+  ptr = &(type->elements[0]);
+
+  while ((*ptr) != NULL)
+    {
+      switch((*ptr) -> type) {
+	case FFI_TYPE_FLOAT:
+	  if (type_set && element != FFI_TYPE_FLOAT) return 0;
+	  if (--n < 0) return FALSE;
+	  type_set = 1;
+	  element = FFI_TYPE_FLOAT;
+	  break;
+	case FFI_TYPE_DOUBLE:
+	  if (type_set && element != FFI_TYPE_DOUBLE) return 0;
+	  if (--n < 0) return FALSE;
+	  type_set = 1;
+	  element = FFI_TYPE_DOUBLE;
+	  break;
+	case FFI_TYPE_STRUCT:
+	  if (!is_homogeneous_fp_aggregate(type, n, &struct_element))
+	      return FALSE;
+	  if (type_set && struct_element != element) return FALSE;
+	  n -= (type -> size)/float_type_size(element);
+	  element = struct_element;
+	  if (n < 0) return FALSE;
+	  break;
+	/* case FFI_TYPE_LONGDOUBLE:
+	  Not yet implemented.	*/
+	default:
+	  return FALSE;
+      }
+      ptr++;
+    }
+  *element_type = element;
+  return TRUE;
+   
+} 
+
+/* ffi_prep_args is called by the assembly routine once stack space
+   has been allocated for the function's arguments.  Returns nonzero
+   if fp registers are used for arguments. */
+
+static bool
+ffi_prep_args(struct ia64_args *stack, extended_cif *ecif, int bytes)
+{
+  register long i, avn;
+  register void **p_argv;
+  register long *argp = stack -> out_regs;
+  register float80 *fp_argp = stack -> fp_regs;
+  register ffi_type **p_arg;
+
+  /* For big return structs, r8 needs to contain the target address.	*/
+  /* Since r8 is otherwise dead, we set it unconditionally.		*/
+  stack -> r8_contents = ecif -> rvalue;
+  i = 0;
+  avn = ecif->cif->nargs;
+  p_arg = ecif->cif->arg_types;
+  p_argv = ecif->avalue;
+  while (i < avn)
+    {
+      size_t z; /* z is in units of arg slots or words, not bytes.	*/
+
+      switch ((*p_arg)->type)
+	{
+	case FFI_TYPE_SINT8:
+	  z = 1;
+	  *(SINT64 *) argp = *(SINT8 *)(* p_argv);
+	  break;
+		  
+	case FFI_TYPE_UINT8:
+	  z = 1;
+	  *(UINT64 *) argp = *(UINT8 *)(* p_argv);
+	  break;
+		  
+	case FFI_TYPE_SINT16:
+	  z = 1;
+	  *(SINT64 *) argp = *(SINT16 *)(* p_argv);
+	  break;
+		  
+	case FFI_TYPE_UINT16:
+	  z = 1;
+	  *(UINT64 *) argp = *(UINT16 *)(* p_argv);
+	  break;
+		  
+	case FFI_TYPE_SINT32:
+	  z = 1;
+	  *(SINT64 *) argp = *(SINT32 *)(* p_argv);
+	  break;
+		  
+	case FFI_TYPE_UINT32:
+	  z = 1;
+	  *(UINT64 *) argp = *(UINT32 *)(* p_argv);
+	  break;
+
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_POINTER:
+	  z = 1;
+	  *(UINT64 *) argp = *(UINT64 *)(* p_argv);
+	  break;
+
+	case FFI_TYPE_FLOAT:
+	  z = 1;
+	  if (fp_argp - stack->fp_regs < 8)
+	    {
+	      /* Note the conversion -- all the fp regs are loaded as
+		 doubles.  */
+	      *fp_argp++ = *(float *)(* p_argv);
+	    }
+	  /* Also put it into the integer registers or memory: */
+	    *(UINT64 *) argp = *(UINT32 *)(* p_argv);
+	  break;
+
+	case FFI_TYPE_DOUBLE:
+	  z = 1;
+	  if (fp_argp - stack->fp_regs < 8)
+	    *fp_argp++ = *(double *)(* p_argv);
+	  /* Also put it into the integer registers or memory: */
+	    *(double *) argp = *(double *)(* p_argv);
+	  break;
+
+	case FFI_TYPE_STRUCT:
+	  {
+	      size_t sz = (*p_arg)->size;
+	      unsigned short element_type;
+              z = ((*p_arg)->size + SIZEOF_ARG - 1)/SIZEOF_ARG;
+	      if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
+		int i;
+		int nelements = sz/float_type_size(element_type);
+		for (i = 0; i < nelements; ++i) {
+		  switch (element_type) {
+		    case FFI_TYPE_FLOAT:
+		      if (fp_argp - stack->fp_regs < 8)
+			*fp_argp++ = ((float *)(* p_argv))[i];
+		      break;
+		    case FFI_TYPE_DOUBLE:
+		      if (fp_argp - stack->fp_regs < 8)
+			*fp_argp++ = ((double *)(* p_argv))[i];
+		      break;
+		    default:
+			/* Extended precision not yet implemented. */
+			abort();
+		  }
+		}
+	      }
+	      /* And pass it in integer registers as a struct, with	*/
+	      /* its actual field sizes packed into registers.		*/
+	      memcpy(argp, *p_argv, (*p_arg)->size);
+	  }
+	  break;
+
+	default:
+	  FFI_ASSERT(0);
+	}
+
+      argp += z;
+      i++, p_arg++, p_argv++;
+    }
+  return (fp_argp != stack -> fp_regs);
+}
+
+/* Perform machine dependent cif processing */
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  long i, avn;
+  bool is_simple = TRUE;
+  long simple_flag = FFI_SIMPLE_V;
+  /* Adjust cif->bytes to include space for the 2 scratch words,
+     r8 register contents, spare word,
+     the 8 fp register contents, and all 8 integer register contents.
+     This will be removed before the call, though 2 scratch words must
+     remain.  */
+
+  cif->bytes += 4*sizeof(long) + 8 *sizeof(float80);
+  if (cif->bytes < sizeof(struct ia64_args))
+    cif->bytes = sizeof(struct ia64_args);
+
+  /* The stack must be double word aligned, so round bytes up
+     appropriately. */
+
+  cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
+
+  avn = cif->nargs;
+  if (avn <= 2) {
+    for (i = 0; i < avn; ++i) {
+      switch(cif -> arg_types[i] -> type) {
+	case FFI_TYPE_SINT32:
+	  simple_flag = FFI_ADD_INT_ARG(simple_flag);
+	  break;
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_POINTER:
+	  simple_flag = FFI_ADD_LONG_ARG(simple_flag);
+	  break;
+	default:
+	  is_simple = FALSE;
+      }
+    }
+  } else {
+    is_simple = FALSE;
+  }
+
+  /* Set the return type flag */
+  switch (cif->rtype->type)
+    {
+    case FFI_TYPE_VOID:
+      cif->flags = FFI_TYPE_VOID;
+      break;
+
+    case FFI_TYPE_STRUCT:
+      {
+        size_t sz = cif -> rtype -> size;
+  	unsigned short element_type;
+
+	is_simple = FALSE;
+  	if (is_homogeneous_fp_aggregate(cif -> rtype, 8, &element_type)) {
+	  int nelements = sz/float_type_size(element_type);
+	  if (nelements <= 1) {
+	    if (0 == nelements) {
+	      cif -> flags = FFI_TYPE_VOID;
+	    } else {
+	      cif -> flags = element_type;
+	    }
+	  } else {
+	    switch(element_type) {
+	      case FFI_TYPE_FLOAT:
+	        cif -> flags = FFI_IS_FLOAT_FP_AGGREGATE | nelements;
+		break;
+	      case FFI_TYPE_DOUBLE:
+	        cif -> flags = FFI_IS_DOUBLE_FP_AGGREGATE | nelements;
+		break;
+	      default:
+		/* long double NYI */
+		abort();
+	    }
+	  }
+	  break;
+        }
+        if (sz <= 32) {
+	  if (sz <= 8) {
+              cif->flags = FFI_TYPE_INT;
+  	  } else if (sz <= 16) {
+              cif->flags = FFI_IS_SMALL_STRUCT2;
+  	  } else if (sz <= 24) {
+              cif->flags = FFI_IS_SMALL_STRUCT3;
+	  } else {
+              cif->flags = FFI_IS_SMALL_STRUCT4;
+	  }
+        } else {
+          cif->flags = FFI_TYPE_STRUCT;
+	}
+      }
+      break;
+
+    case FFI_TYPE_FLOAT:
+      is_simple = FALSE;
+      cif->flags = FFI_TYPE_FLOAT;
+      break;
+
+    case FFI_TYPE_DOUBLE:
+      is_simple = FALSE;
+      cif->flags = FFI_TYPE_DOUBLE;
+      break;
+
+    default:
+      cif->flags = FFI_TYPE_INT;
+      /* This seems to depend on little endian mode, and the fact that	*/
+      /* the return pointer always points to at least 8 bytes.  But 	*/
+      /* that also seems to be true for other platforms.		*/
+      break;
+    }
+  
+  if (is_simple) cif -> flags |= simple_flag;
+  return FFI_OK;
+}
+
+extern int ffi_call_unix(bool (*)(struct ia64_args *, extended_cif *, int), 
+			 extended_cif *, unsigned, 
+			 unsigned, unsigned *, void (*)());
+
+void
+ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+{
+  extended_cif ecif;
+  long simple = cif -> flags & FFI_SIMPLE;
+
+  /* Should this also check for Unix ABI? */
+  /* This is almost, but not quite, machine independent.  Note that	*/
+  /* we can get away with not caring about length of the result because	*/
+  /* we assume we are little endian, and the result buffer is large 	*/
+  /* enough.								*/
+  /* This needs work for HP/UX.						*/
+  if (simple) {
+    long (*lfn)() = (long (*)())fn;
+    long result;
+    switch(simple) {
+      case FFI_SIMPLE_V:
+	result = lfn();
+	break;
+      case FFI_SIMPLE_I:
+	result = lfn(*(int *)avalue[0]);
+	break;
+      case FFI_SIMPLE_L:
+	result = lfn(*(long *)avalue[0]);
+	break;
+      case FFI_SIMPLE_II:
+	result = lfn(*(int *)avalue[0], *(int *)avalue[1]);
+	break;
+      case FFI_SIMPLE_IL:
+	result = lfn(*(int *)avalue[0], *(long *)avalue[1]);
+	break;
+      case FFI_SIMPLE_LI:
+	result = lfn(*(long *)avalue[0], *(int *)avalue[1]);
+	break;
+      case FFI_SIMPLE_LL:
+	result = lfn(*(long *)avalue[0], *(long *)avalue[1]);
+	break;
+    }
+    if ((cif->flags & ~FFI_SIMPLE) != FFI_TYPE_VOID && 0 != rvalue) {
+      * (long *)rvalue = result;
+    }
+    return;
+  }
+  ecif.cif = cif;
+  ecif.avalue = avalue;
+  
+  /* If the return value is a struct and we don't have a return
+     value address then we need to make one.  */
+  
+  if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT)
+    ecif.rvalue = alloca(cif->rtype->size);
+  else
+    ecif.rvalue = rvalue;
+    
+  switch (cif->abi) 
+    {
+    case FFI_UNIX:
+      ffi_call_unix(ffi_prep_args, &ecif, cif->bytes,
+		    cif->flags, rvalue, fn);
+      break;
+
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+}
+
+/*
+ * Closures represent a pair consisting of a function pointer, and
+ * some user data.  A closure is invoked by reinterpreting the closure
+ * as a function pointer, and branching to it.  Thus we can make an
+ * interpreted function callable as a C function:  We turn the interpreter
+ * itself, together with a pointer specifying the interpreted procedure,
+ * into a closure.
+ * On X86, the first few words of the closure structure actually contain code,
+ * which will do the right thing.  On most other architectures, this
+ * would raise some Icache/Dcache coherence issues (which can be solved, but
+ * often not cheaply).
+ * For IA64, function pointer are already pairs consisting of a code
+ * pointer, and a gp pointer.  The latter is needed to access global variables.
+ * Here we set up such a pair as the first two words of the closure (in
+ * the "trampoline" area), but we replace the gp pointer with a pointer
+ * to the closure itself.  We also add the real gp pointer to the
+ * closure.  This allows the function entry code to both retrieve the
+ * user data, and to restire the correct gp pointer.
+ */
+
+static void 
+ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
+			    void **avalue, ffi_cif *cif);
+
+/* This function is entered with the doctored gp (r1) value.
+ * This code is extremely gcc specific.  There is some argument that
+ * it should really be written in assembly code, since it depends on
+ * gcc properties that might change over time.
+ */
+
+/* ffi_closure_UNIX is an assembly routine, which copies the register 	*/
+/* state into s struct ia64_args, and the invokes			*/
+/* ffi_closure_UNIX_inner.  It also recovers the closure pointer	*/
+/* from its fake gp pointer.						*/
+void ffi_closure_UNIX();
+
+#ifndef __GNUC__
+#   error This requires gcc
+#endif
+void
+ffi_closure_UNIX_inner (ffi_closure *closure, struct ia64_args * args)
+/* Hopefully declarint this as a varargs function will force all args	*/
+/* to memory.								*/
+{
+  // this is our return value storage
+  long double    res;
+
+  // our various things...
+  ffi_cif       *cif;
+  unsigned short rtype;
+  void          *resp;
+  void		**arg_area;
+
+  resp = (void*)&res;
+  cif         = closure->cif;
+  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
+
+  /* this call will initialize ARG_AREA, such that each
+   * element in that array points to the corresponding 
+   * value on the stack; and if the function returns
+   * a structure, it will re-set RESP to point to the
+   * structure return address.  */
+
+  ffi_prep_incoming_args_UNIX(args, (void**)&resp, arg_area, cif);
+  
+  (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+  rtype = cif->flags;
+
+  /* now, do a generic return based on the value of rtype */
+  if (rtype == FFI_TYPE_INT)
+    {
+      asm volatile ("ld8 r8=[%0]" : : "r" (resp) : "r8");
+    }
+  else if (rtype == FFI_TYPE_FLOAT)
+    {
+      asm volatile ("ldfs f8=[%0]" : : "r" (resp) : "f8");
+    }
+  else if (rtype == FFI_TYPE_DOUBLE)
+    {
+      asm volatile ("ldfd f8=[%0]" : : "r" (resp) : "f8");
+    }
+  else if (rtype == FFI_IS_SMALL_STRUCT2)
+    {
+      asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"
+		    : : "r" (resp), "r" (resp+8) : "r8","r9");
+    }
+  else if (rtype == FFI_IS_SMALL_STRUCT3)
+    {
+      asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"
+		    : : "r" (resp), "r" (resp+8), "r" (resp+16)
+		    : "r8","r9","r10");
+    }
+  else if (rtype == FFI_IS_SMALL_STRUCT4)
+    {
+      asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"
+		    : : "r" (resp), "r" (resp+8), "r" (resp+16), "r" (resp+24)
+		    : "r8","r9","r10","r11");
+    }
+  else if (rtype != FFI_TYPE_VOID && rtype != FFI_TYPE_STRUCT)
+    {
+      /* Can only happen for homogeneous FP aggregates?	*/
+      abort();
+    }
+}
+
+static void 
+ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
+			    void **avalue, ffi_cif *cif)
+{
+  register unsigned int i;
+  register unsigned int avn;
+  register void **p_argv;
+  register unsigned long *argp = args -> out_regs;
+  unsigned fp_reg_num = 0;
+  register ffi_type **p_arg;
+
+  avn = cif->nargs;
+  p_argv = avalue;
+
+  for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++)
+    {
+      size_t z; /* In units of words or argument slots.	*/
+
+      switch ((*p_arg)->type)
+	{
+	case FFI_TYPE_SINT8:
+	case FFI_TYPE_UINT8:
+	case FFI_TYPE_SINT16:
+	case FFI_TYPE_UINT16:
+	case FFI_TYPE_SINT32:
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+	case FFI_TYPE_POINTER:
+	  z = 1;
+	  *p_argv = (void *)argp;
+	  break;
+		  
+	case FFI_TYPE_FLOAT:
+	  z = 1;
+	  /* Convert argument back to float in place from the saved value */
+	  if (fp_reg_num < 8) {
+	      *(float *)argp = args -> fp_regs[fp_reg_num++];
+	  } else {
+	      *(float *)argp = *(double *)argp;
+	  }
+	  *p_argv = (void *)argp;
+	  break;
+
+	case FFI_TYPE_DOUBLE:
+	  z = 1;
+	  if (fp_reg_num < 8) {
+	      *p_argv = args -> fp_regs + fp_reg_num++;
+	  } else {
+	      *p_argv = (void *)argp;
+	  }
+	  break;
+
+	case FFI_TYPE_STRUCT:
+	  {
+	      size_t sz = (*p_arg)->size;
+	      unsigned short element_type;
+              z = ((*p_arg)->size + SIZEOF_ARG - 1)/SIZEOF_ARG;
+	      if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
+		int nelements = sz/float_type_size(element_type);
+		if (nelements + fp_reg_num >= 8) {
+		  /* hard case NYI.	*/
+		  abort();
+		}
+		if (element_type == FFI_TYPE_DOUBLE) {
+	          *p_argv = args -> fp_regs + fp_reg_num;
+		  fp_reg_num += nelements;
+		  break;
+		}
+		if (element_type == FFI_TYPE_FLOAT) {
+		  int j;
+		  for (j = 0; j < nelements; ++ j) {
+		     ((float *)argp)[j] = args -> fp_regs[fp_reg_num + j];
+		  }
+	          *p_argv = (void *)argp;
+		  fp_reg_num += nelements;
+		  break;
+		}
+		abort();  /* Other fp types NYI */
+	      }
+	  }
+	  break;
+
+	default:
+	  FFI_ASSERT(0);
+	}
+
+      argp += z;
+      p_argv++;
+
+    }
+  
+  return;
+}
+
+
+/* Fill in a closure to refer to the specified fun and user_data.	*/
+/* cif specifies the argument and result types for fun.			*/
+/* the cif must already be prep'ed */
+
+/* The layout of a function descriptor.  A C function pointer really 	*/
+/* points to one of these.						*/
+typedef struct ia64_fd_struct {
+    void *code_pointer;
+    void *gp;
+} ia64_fd;
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+		  ffi_cif* cif,
+		  void (*fun)(ffi_cif*,void*,void**,void*),
+		  void *user_data)
+{
+  struct ffi_ia64_trampoline_struct *tramp =
+    (struct ffi_ia64_trampoline_struct *) (closure -> tramp);
+  ia64_fd *fd = (ia64_fd *)(void *)ffi_closure_UNIX;
+
+  FFI_ASSERT (cif->abi == FFI_UNIX);
+
+  tramp -> code_pointer = fd -> code_pointer;
+  tramp -> real_gp = fd -> gp;
+  tramp -> fake_gp = closure;
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
+
+  return FFI_OK;
+}
+
+
Index: src/ia64/ia64_flags.h
===================================================================
RCS file: ia64_flags.h
diff -N ia64_flags.h
--- /dev/null	Tue May  5 13:32:27 1998
+++ ia64_flags.h	Fri Feb 25 11:02:28 2000
@@ -0,0 +1,62 @@
+/* -----------------------------------------------------------------------
+   ia64_flags.h - Copyright (c) 2000 Hewlett Packard Company
+   
+   IA64/unix Foreign Function Interface 
+
+   Original author: Hans Boehm, HP Labs
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+
+/* Homogeneous Floating Point Aggregates (HFAs) which are returned	*/
+/* in FP registers.  The least significant bits specify the size in 	*/
+/* words.								*/
+#define FFI_IS_FLOAT_FP_AGGREGATE 0x1000
+#define FFI_IS_DOUBLE_FP_AGGREGATE 0x0800
+#define FLOAT_FP_AGGREGATE_BIT 12
+#define DOUBLE_FP_AGGREGATE_BIT 11
+
+/* Small structures containing N words.  If N=1, they are returned	*/
+/* as though they were integers.					*/
+#define FFI_IS_SMALL_STRUCT2	0x40 /* Struct > 8, <=16 bytes	*/
+#define FFI_IS_SMALL_STRUCT3	0x41 /* Struct > 16 <= 24 bytes	*/
+#define FFI_IS_SMALL_STRUCT4	0x42 /* Struct > 24, <=32 bytes	*/
+
+/* Flag values identifying particularly simple cases, which are 	*/
+/* handled specially.  We treat functions as simple if they take all	*/
+/* arguments can be passed as 32 or 64 bit integer quantities, there is	*/
+/* either no return value or it can be treated as a 64bit integer, and	*/
+/* if there are at most 2 arguments.					*/
+/* This is OR'ed with the normal flag values.				*/
+#define FFI_SIMPLE_V 0x10000	/* () -> X	*/
+#define FFI_SIMPLE_I 0x20000	/* (int) -> X	*/
+#define FFI_SIMPLE_L 0x30000	/* (long) -> X	*/
+#define FFI_SIMPLE_II 0x40000	/* (int,int) -> X	*/
+#define FFI_SIMPLE_IL 0x50000	/* (int,long) -> X	*/
+#define FFI_SIMPLE_LI 0x60000	/* (long,int) -> X	*/
+#define FFI_SIMPLE_LL 0x70000	/* (long,long) -> X	*/
+
+/* Mask for all of the FFI_SIMPLE bits:	*/
+#define FFI_SIMPLE 0xf0000
+
+/* An easy way to build FFI_SIMPLE flags from FFI_SIMPLE_V:	*/
+#define FFI_ADD_LONG_ARG(flag) (((flag) << 1) | 0x10000)
+#define FFI_ADD_INT_ARG(flag) ((flag) << 1)
Index: src/ia64/unix.S
===================================================================
RCS file: unix.S
diff -N unix.S
--- /dev/null	Tue May  5 13:32:27 1998
+++ unix.S	Fri Feb 25 11:02:28 2000
@@ -0,0 +1,301 @@
+/* -----------------------------------------------------------------------
+   unix.S - Copyright (c) 1998 Cygnus Solutions
+            Copyright (c) 2000 Hewlett Packard Company
+   
+   IA64/unix Foreign Function Interface 
+
+   Primary author: Hans Boehm, HP Labs
+
+   Loosely modeled on Cygnus code for other platforms.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM	
+#include <ffi.h>
+#include "ia64_flags.h"
+
+/* parameters:	*/
+#define callback	in0
+#define ecifp		in1
+#define bytes		in2
+#define flags		in3
+#define raddr		in4
+#define fn		in5
+
+#define FLOAT_SZ	8 /* in-memory size of fp operands	*/
+
+.text
+        .align 16
+        .global ffi_call_unix#
+        .proc ffi_call_unix#
+ffi_call_unix:
+	alloc   loc0=ar.pfs,6,5,8,0
+	mov 	loc1=b0;
+	sub	sp=sp,bytes
+	mov	loc4=r1		/* Save gp 	*/
+	ld8	r8=[callback],8	/* code address of callback	*/
+	;;
+	mov 	out0=sp
+	mov	out1=ecifp
+	mov	out2=bytes
+	ld8	r1=[callback]	/* Set up gp for callback.  Unnecessary? */
+	mov	b6=r8
+	;;
+	br.call.sptk.many b0 = b6	/* call ffi_prep_args		*/
+	cmp.eq	p6,p0=0,r8		/* r8 nonzero ==> need fp regs	*/
+ 	;;
+(p6)	add	loc2=32+8*FLOAT_SZ,sp
+(p6)	br.cond.dptk.many	fp_done
+	;;	/* Quiets warning; needed?	*/
+	add	loc2=32,sp
+	add	loc3=32+FLOAT_SZ,sp
+	;;
+	ldfd	f8=[loc2],2*FLOAT_SZ
+	ldfd	f9=[loc3],2*FLOAT_SZ
+	;;
+	ldfd	f10=[loc2],2*FLOAT_SZ
+	ldfd	f11=[loc3],2*FLOAT_SZ
+	;;
+	ldfd	f12=[loc2],2*FLOAT_SZ
+	ldfd	f13=[loc3],2*FLOAT_SZ
+	;;
+	ldfd	f14=[loc2],2*FLOAT_SZ
+	ldfd	f15=[loc3]
+fp_done:
+	add	r9=16,sp	/* Pointer to r8_contents	*/
+	/* loc2 points at first integer register value.  */
+	add	loc3=8,loc2
+	;;
+	ld8	r8=[r9]		/* Just in case we return large struct */
+	ld8	out0=[loc2],16
+	ld8	out1=[loc3],16
+	;;
+	ld8	out2=[loc2],16
+	ld8	out3=[loc3],16
+	;;
+	ld8	out4=[loc2],16
+	ld8	out5=[loc3],16
+	;;
+	ld8	out6=[loc2],16
+	ld8	out7=[loc3]
+	/* loc2 points at first stack parameter.  Set sp to 16 bytes	*/
+	/* below that.							*/
+	add	sp=-16,loc2
+	
+	ld8 	r8=[fn],8
+	;;
+	ld8	r1=[fn]		/* Set up gp */
+	mov	b6=r8;;
+	br.call.sptk.many b0 = b6	/* call ffi_prep_args	*/
+	
+	/* Handle return value. */
+	cmp.eq	p6,p0=0,raddr
+	cmp.eq	p7,p0=FFI_TYPE_INT,flags
+	cmp.eq	p10,p0=FFI_IS_SMALL_STRUCT2,flags
+	cmp.eq	p11,p0=FFI_IS_SMALL_STRUCT3,flags
+	cmp.eq	p12,p0=FFI_IS_SMALL_STRUCT4,flags
+	;;
+(p6) 	br.cond.dpnt.few done		/* Dont copy ret values if raddr = 0 */
+(p7)	br.cond.dptk.few copy1
+(p10)	br.cond.dpnt.few copy2
+(p11)	br.cond.dpnt.few copy3
+(p12)	br.cond.dpnt.few copy4
+	cmp.eq	p8,p0=FFI_TYPE_FLOAT,flags
+	cmp.eq	p9,p0=FFI_TYPE_DOUBLE,flags
+	tbit.nz	p6,p0=flags,FLOAT_FP_AGGREGATE_BIT
+	tbit.nz	p7,p0=flags,DOUBLE_FP_AGGREGATE_BIT
+	;;
+(p8)	stfs	[raddr]=f8
+(p9)	stfd	[raddr]=f8
+	;;
+(p6)	br.cond.dpnt.few handle_float_hfa
+(p7)	br.cond.dpnt.few handle_double_hfa
+	br done
+
+copy4:
+	add	loc3=24,raddr
+	;;
+	st8	[loc3]=r11
+copy3:
+	add	loc3=16,raddr
+	;;
+	st8	[loc3]=r10
+copy2:
+	add	loc3=8,raddr
+	;;
+	st8	[loc3]=r9
+copy1:
+	st8	[raddr]=r8
+	/* In the big struct case, raddr was passed as an argument.	*/
+	/* In the void case there was nothing to do.			*/
+
+done:
+	mov	r1=loc4		/* Restore gp	*/
+	mov	ar.pfs = loc0
+	mov	b0 = loc1
+	br.ret.sptk.many b0
+
+handle_double_hfa:
+	/* Homogeneous floating point array of doubles is returned in	*/
+	/* registers f8-f15.  Save one at a time to return area.	*/
+	and	flags=0xf,flags	/* Retrieve size	*/
+	;;
+	cmp.eq	p6,p0=2,flags
+	cmp.eq	p7,p0=3,flags
+	cmp.eq	p8,p0=4,flags
+	cmp.eq	p9,p0=5,flags
+	cmp.eq	p10,p0=6,flags
+	cmp.eq	p11,p0=7,flags
+	cmp.eq	p12,p0=8,flags
+	;;
+(p6)	br.cond.dptk.few	dhfa2
+(p7)	br.cond.dptk.few	dhfa3
+(p8)	br.cond.dptk.few	dhfa4
+(p9)	br.cond.dptk.few	dhfa5
+(p10)	br.cond.dptk.few	dhfa6
+(p11)	br.cond.dptk.few	dhfa7
+dhfa8:	add 	loc3=7*8,raddr
+	;;
+	stfd	[loc3]=f15
+dhfa7:	add 	loc3=6*8,raddr
+	;;
+	stfd	[loc3]=f14
+dhfa6:	add 	loc3=5*8,raddr
+	;;
+	stfd	[loc3]=f13
+dhfa5:	add 	loc3=4*8,raddr
+	;;
+	stfd	[loc3]=f12
+dhfa4:	add 	loc3=3*8,raddr
+	;;
+	stfd	[loc3]=f11
+dhfa3:	add 	loc3=2*8,raddr
+	;;
+	stfd	[loc3]=f10
+dhfa2:	add 	loc3=1*8,raddr
+	;;
+	stfd	[loc3]=f9
+	stfd	[raddr]=f8
+	br	done
+
+handle_float_hfa:
+	/* Homogeneous floating point array of floats is returned in	*/
+	/* registers f8-f15.  Save one at a time to return area.	*/
+	and	flags=0xf,flags	/* Retrieve size	*/
+	;;
+	cmp.eq	p6,p0=2,flags
+	cmp.eq	p7,p0=3,flags
+	cmp.eq	p8,p0=4,flags
+	cmp.eq	p9,p0=5,flags
+	cmp.eq	p10,p0=6,flags
+	cmp.eq	p11,p0=7,flags
+	cmp.eq	p12,p0=8,flags
+	;;
+(p6)	br.cond.dptk.few	shfa2
+(p7)	br.cond.dptk.few	shfa3
+(p8)	br.cond.dptk.few	shfa4
+(p9)	br.cond.dptk.few	shfa5
+(p10)	br.cond.dptk.few	shfa6
+(p11)	br.cond.dptk.few	shfa7
+shfa8:	add 	loc3=7*4,raddr
+	;;
+	stfd	[loc3]=f15
+shfa7:	add 	loc3=6*4,raddr
+	;;
+	stfd	[loc3]=f14
+shfa6:	add 	loc3=5*4,raddr
+	;;
+	stfd	[loc3]=f13
+shfa5:	add 	loc3=4*4,raddr
+	;;
+	stfd	[loc3]=f12
+shfa4:	add 	loc3=3*4,raddr
+	;;
+	stfd	[loc3]=f11
+shfa3:	add 	loc3=2*4,raddr
+	;;
+	stfd	[loc3]=f10
+shfa2:	add 	loc3=1*4,raddr
+	;;
+	stfd	[loc3]=f9
+	stfd	[raddr]=f8
+	br	done
+
+        .endp ffi_call_unix
+
+
+.text
+        .align 16
+        .global ffi_closure_UNIX
+        .proc ffi_closure_UNIX
+ffi_closure_UNIX:
+	alloc   loc0=ar.pfs,8,2,2,0
+	mov	loc1=b0
+	/* Retrieve closure pointer and real gp.	*/
+	mov	out0=gp
+	add	gp=16,gp
+	;;
+	ld8	gp=[gp]
+	/* Reserve a structia64_args on the stack such that arguments	*/
+	/* past the first 8 are automatically placed in the right	*/
+	/* slot.  Note that when we start the sp points at 2 8-byte	*/
+	/* scratch words, followed by the extra arguments.		*/
+#	define BASIC_ARGS_SZ (8*FLOAT_SZ+8*8+2*8)
+#	define FIRST_FP_OFFSET (4*8)
+	add	r14=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET),sp
+	add	r15=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET-FLOAT_SZ),sp
+	add	sp=-BASIC_ARGS_SZ,sp
+	/* r14 points to fp_regs[0], r15 points to fp_regs[1]	*/
+	;;
+	stfd	[r14]=f8,2*FLOAT_SZ
+	stfd	[r15]=f9,2*FLOAT_SZ
+	;;
+	stfd	[r14]=f10,2*FLOAT_SZ
+	stfd	[r15]=f11,2*FLOAT_SZ
+	;;
+	stfd	[r14]=f12,2*FLOAT_SZ
+	stfd	[r15]=f13,2*FLOAT_SZ
+	;;
+	stfd	[r14]=f14,FLOAT_SZ+8
+	stfd	[r15]=f15,2*8
+	;;
+	/* r14 points to first parameter register area, r15 to second. */
+	st8	[r14]=in0,2*8
+	st8	[r15]=in1,2*8
+	;;
+	st8	[r14]=in2,2*8
+	st8	[r15]=in3,2*8
+	;;
+	st8	[r14]=in4,2*8
+	st8	[r15]=in5,2*8
+	;;
+	st8	[r14]=in6,2*8
+	st8	[r15]=in7,2*8
+	/* Call ffi_closure_UNIX_inner */
+	mov	out1=sp
+	br.call.sptk.many b0=ffi_closure_UNIX_inner
+	;;
+	mov	b0=loc1
+	mov 	ar.pfs=loc0
+	br.ret.sptk.many b0
+	.endp ffi_closure_UNIX
+	
+

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]