This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Patch] libffi: Add MIPS64 support.


David Daney wrote:
Maciej W. Rozycki wrote:
On Thu, 9 Aug 2007, Richard Sandiford wrote:

In the first case, you are probably correct. We are copying the pointer into a wider type. In practice it does not matter because all valid user space pointers have the high bit clear so there would never be a case where the not sign extending would produce a different result than if you did sign extend.
Ah, so we don't support running libffi from kernel space? I was assuming
we needed to cope with both. If we don't, it is indeed a non-issue.

It sounds like carelessness to me -- I would watch out.

Indeed. I will fix it before committing.
This is the patch I actually committed.

The only changes from the previous version were to treat pointers as signed instead of unsigned, and a small change to a comment in n32.S.

Tested on mips64-linux {o32, n32, n64} with zero failures.

2007-08-10 David Daney <ddaney@avtrex.com>

   PR libffi/28313
   * configure.ac: Don't treat mips64 as a special case.
   * Makefile.am (nodist_libffi_la_SOURCES): Add n32.S.
   * configure: Regenerate
   * Makefile.in: Ditto.
   * fficonfig.h.in: Ditto.
   * src/mips/ffitarget.h (REG_L, REG_S, SUBU, ADDU, SRL, LI): Indent.
   (LA, EH_FRAME_ALIGN, FDE_ADDR_BYTES): New preprocessor macros.
   (FFI_DEFAULT_ABI): Set for n64 case.
   (FFI_CLOSURES, FFI_TRAMPOLINE_SIZE): Define for n32 and n64 cases.
   * src/mips/n32.S (ffi_call_N32): Add debug macros and labels for FDE.
   (ffi_closure_N32): New function.
   (.eh_frame): New section
   * src/mips/o32.S: Clean up comments.
   (ffi_closure_O32): Pass ffi_closure parameter in $12.
   * src/mips/ffi.c: Use FFI_MIPS_N32 instead of
   _MIPS_SIM == _ABIN32 throughout.
   (FFI_MIPS_STOP_HERE): New, use in place of
   ffi_stop_here.
   (ffi_prep_args): Use unsigned long to hold pointer values.  Rewrite
   to support n32/n64 ABIs.
   (calc_n32_struct_flags): Rewrite.
   (calc_n32_return_struct_flags): Remove unused variable.  Reverse
   position of flag bits.
   (ffi_prep_cif_machdep): Rewrite n32 portion.
   (ffi_call): Enable for n64.  Add special handling for small structure
   return values.
   (ffi_prep_closure_loc): Add n32 and n64 support.
   (ffi_closure_mips_inner_O32): Add cast to silence warning.
   (copy_struct_N32, ffi_closure_mips_inner_N32): New functions.

Index: configure
===================================================================
--- configure	(revision 127010)
+++ configure	(working copy)
@@ -10324,8 +10324,6 @@ case "$host" in
 	TARGET=M68K; TARGETDIR=m68k
 	;;
 
-  mips64*-*)
-	;;
   mips-sgi-irix5.* | mips-sgi-irix6.*)
 	TARGET=MIPS_IRIX; TARGETDIR=mips
 	;;
Index: configure.ac
===================================================================
--- configure.ac	(revision 127010)
+++ configure.ac	(working copy)
@@ -94,8 +94,6 @@ case "$host" in
 	TARGET=M68K; TARGETDIR=m68k
 	;;
 
-  mips64*-*)
-	;;
   mips-sgi-irix5.* | mips-sgi-irix6.*)
 	TARGET=MIPS_IRIX; TARGETDIR=mips
 	;;
Index: fficonfig.h.in
===================================================================
--- fficonfig.h.in	(revision 127010)
+++ fficonfig.h.in	(working copy)
@@ -37,6 +37,9 @@
    */
 #undef HAVE_AS_SPARC_UA_PCREL
 
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
 /* Define if __attribute__((visibility("hidden"))) is supported. */
 #undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
 
@@ -91,6 +94,10 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
 /* Define to 1 if your C compiler doesn't accept -c and -o together. */
 #undef NO_MINUS_C_MINUS_O
 
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 127010)
+++ Makefile.am	(working copy)
@@ -88,7 +88,7 @@ if MIPS_IRIX
 nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 endif
 if MIPS_LINUX
-nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S
+nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 endif
 if X86
 nodist_libffi_la_SOURCES += src/x86/ffi.c src/x86/sysv.S
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 127010)
+++ Makefile.in	(working copy)
@@ -38,7 +38,7 @@ build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
 @MIPS_IRIX_TRUE@am__append_1 = src/mips/ffi.c src/mips/o32.S src/mips/n32.S
-@MIPS_LINUX_TRUE@am__append_2 = src/mips/ffi.c src/mips/o32.S
+@MIPS_LINUX_TRUE@am__append_2 = src/mips/ffi.c src/mips/o32.S src/mips/n32.S
 @X86_TRUE@am__append_3 = src/x86/ffi.c src/x86/sysv.S
 @X86_WIN32_TRUE@am__append_4 = src/x86/ffi.c src/x86/win32.S
 @X86_DARWIN_TRUE@am__append_5 = src/x86/ffi.c src/x86/darwin.S src/x86/ffi64.c src/x86/darwin64.S
@@ -97,7 +97,8 @@ am_libffi_la_OBJECTS = src/debug.lo src/
 	src/raw_api.lo src/java_raw_api.lo src/closures.lo
 @MIPS_IRIX_TRUE@am__objects_1 = src/mips/ffi.lo src/mips/o32.lo \
 @MIPS_IRIX_TRUE@	src/mips/n32.lo
-@MIPS_LINUX_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo
+@MIPS_LINUX_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo \
+@MIPS_LINUX_TRUE@	src/mips/n32.lo
 @X86_TRUE@am__objects_3 = src/x86/ffi.lo src/x86/sysv.lo
 @X86_WIN32_TRUE@am__objects_4 = src/x86/ffi.lo src/x86/win32.lo
 @X86_DARWIN_TRUE@am__objects_5 = src/x86/ffi.lo src/x86/darwin.lo \
Index: src/mips/ffitarget.h
===================================================================
--- src/mips/ffitarget.h	(revision 127010)
+++ src/mips/ffitarget.h	(working copy)
@@ -104,19 +104,28 @@
 #define ra $31		
 
 #ifdef FFI_MIPS_O32
-#define REG_L	lw
-#define REG_S	sw
-#define SUBU	subu
-#define ADDU	addu
-#define SRL	srl
-#define LI	li
+# define REG_L	lw
+# define REG_S	sw
+# define SUBU	subu
+# define ADDU	addu
+# define SRL	srl
+# define LI	li
 #else /* !FFI_MIPS_O32 */
-#define REG_L	ld
-#define REG_S	sd
-#define SUBU	dsubu
-#define ADDU	daddu
-#define SRL	dsrl
-#define LI 	dli
+# define REG_L	ld
+# define REG_S	sd
+# define SUBU	dsubu
+# define ADDU	daddu
+# define SRL	dsrl
+# define LI 	dli
+# if (_MIPS_SIM==_ABI64)
+#  define LA dla
+#  define EH_FRAME_ALIGN 3
+#  define FDE_ADDR_BYTES .8byte
+# else
+#  define LA la
+#  define EH_FRAME_ALIGN 2
+#  define FDE_ADDR_BYTES .4byte
+# endif /* _MIPS_SIM==_ABI64 */
 #endif /* !FFI_MIPS_O32 */
 #else /* !LIBFFI_ASM */
 #ifdef FFI_MIPS_O32
@@ -143,7 +152,11 @@ typedef enum ffi_abi {
   FFI_DEFAULT_ABI = FFI_O32,
 #endif
 #else
+# if _MIPS_SIM==_ABI64
+  FFI_DEFAULT_ABI = FFI_N64,
+# else
   FFI_DEFAULT_ABI = FFI_N32,
+# endif
 #endif
 
   FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
@@ -158,8 +171,13 @@ typedef enum ffi_abi {
 #define FFI_CLOSURES 1
 #define FFI_TRAMPOLINE_SIZE 20
 #else
-/* N32/N64 not implemented yet. */
-#define FFI_CLOSURES 0
+/* N32/N64. */
+# define FFI_CLOSURES 1
+#if _MIPS_SIM==_ABI64
+#define FFI_TRAMPOLINE_SIZE 52
+#else
+#define FFI_TRAMPOLINE_SIZE 20
+#endif
 #endif /* FFI_MIPS_O32 */
 #define FFI_NATIVE_RAW_API 0
 
Index: src/mips/n32.S
===================================================================
--- src/mips/n32.S	(revision 127010)
+++ src/mips/n32.S	(working copy)
@@ -45,13 +45,19 @@
 	.globl	ffi_call_N32
 	.ent	ffi_call_N32
 ffi_call_N32:	
+.LFB3:
+	.frame	$fp, SIZEOF_FRAME, ra
+	.mask	0xc0000000,-FFI_SIZEOF_ARG
+	.fmask	0x00000000,0
 
 	# Prologue
 	SUBU	$sp, SIZEOF_FRAME			# Frame size
+.LCFI0:
 	REG_S	$fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp)	# Save frame pointer
 	REG_S	ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp)	# Save return address
+.LCFI1:
 	move	$fp, $sp
-
+.LCFI3:
 	move	t9, callback	# callback function pointer
 	REG_S	bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
 	REG_S	flags, 3*FFI_SIZEOF_ARG($fp) # flags
@@ -315,6 +321,224 @@ epilogue:	
 	ADDU	$sp, SIZEOF_FRAME		      # Fix stack pointer
 	j	ra
 
+.LFE3:
 	.end	ffi_call_N32
+
+/* ffi_closure_N32. Expects address of the passed-in ffi_closure in t0
+   ($12). Stores any arguments passed in registers onto the stack,
+   then calls ffi_closure_mips_inner_N32, which then decodes
+   them.
+	
+	Stack layout:
+
+	20 - Start of parameters, original sp
+	19 - Called function a7 save
+	18 - Called function a6 save
+	17 - Called function a5 save
+	16 - Called function a4 save
+	15 - Called function a3 save
+	14 - Called function a2 save
+	13 - Called function a1 save
+	12 - Called function a0 save
+	11 - Called function f19
+	10 - Called function f18
+	 9 - Called function f17
+	 8 - Called function f16
+	 7 - Called function f15
+         6 - Called function f14
+         5 - Called function f13
+         4 - Called function f12
+	 3 - return value high (v1 or $f2)
+	 2 - return value low (v0 or $f0)
+	 1 - ra save
+	 0 - gp save our sp  points here
+	 */
+
+#define SIZEOF_FRAME2	(20 * FFI_SIZEOF_ARG)
+	
+#define A7_OFF2		(19 * FFI_SIZEOF_ARG)
+#define A6_OFF2		(18 * FFI_SIZEOF_ARG)
+#define A5_OFF2		(17 * FFI_SIZEOF_ARG)
+#define A4_OFF2		(16 * FFI_SIZEOF_ARG)
+#define A3_OFF2		(15 * FFI_SIZEOF_ARG)
+#define A2_OFF2		(14 * FFI_SIZEOF_ARG)
+#define A1_OFF2		(13 * FFI_SIZEOF_ARG)
+#define A0_OFF2		(12 * FFI_SIZEOF_ARG)	
+
+#define F19_OFF2	(11 * FFI_SIZEOF_ARG)
+#define F18_OFF2	(10 * FFI_SIZEOF_ARG)
+#define F17_OFF2	(9  * FFI_SIZEOF_ARG)
+#define F16_OFF2	(8  * FFI_SIZEOF_ARG)
+#define F15_OFF2	(7  * FFI_SIZEOF_ARG)
+#define F14_OFF2	(6  * FFI_SIZEOF_ARG)
+#define F13_OFF2	(5  * FFI_SIZEOF_ARG)
+#define F12_OFF2	(4  * FFI_SIZEOF_ARG)
+
+#define V1_OFF2		(3  * FFI_SIZEOF_ARG)
+#define V0_OFF2		(2  * FFI_SIZEOF_ARG)
+
+#define RA_OFF2		(1  * FFI_SIZEOF_ARG)
+#define GP_OFF2		(0  * FFI_SIZEOF_ARG)
+
+	.align	2
+	.globl	ffi_closure_N32
+	.ent	ffi_closure_N32
+ffi_closure_N32:
+.LFB2:
+	.frame	$sp, SIZEOF_FRAME2, ra
+	.mask	0x90000000,-(SIZEOF_FRAME2 - RA_OFF2)
+	.fmask	0x00000000,0
+	SUBU	$sp, SIZEOF_FRAME2
+.LCFI5:
+	.cpsetup t9, GP_OFF2, ffi_closure_N32
+	REG_S	ra, RA_OFF2($sp)	# Save return address
+.LCFI6:
+	# Store all possible argument registers. If there are more than
+	# fit in registers, then they were stored on the stack.
+	REG_S	a0, A0_OFF2($sp)
+	REG_S	a1, A1_OFF2($sp)
+	REG_S	a2, A2_OFF2($sp)
+	REG_S	a3, A3_OFF2($sp)
+	REG_S	a4, A4_OFF2($sp)
+	REG_S	a5, A5_OFF2($sp)
+	REG_S	a6, A6_OFF2($sp)
+	REG_S	a7, A7_OFF2($sp)
+
+	# Store all possible float/double registers.
+	s.d	$f12, F12_OFF2($sp)
+	s.d	$f13, F13_OFF2($sp)
+	s.d	$f14, F14_OFF2($sp)
+	s.d	$f15, F15_OFF2($sp)
+	s.d	$f16, F16_OFF2($sp)
+	s.d	$f17, F17_OFF2($sp)
+	s.d	$f18, F18_OFF2($sp)
+	s.d	$f19, F19_OFF2($sp)
+
+	# Call ffi_closure_mips_inner_N32 to do the real work.
+	LA	t9, ffi_closure_mips_inner_N32
+	move	a0, $12	 # Pointer to the ffi_closure
+	addu	a1, $sp, V0_OFF2
+	addu	a2, $sp, A0_OFF2
+	addu	a3, $sp, F12_OFF2
+	jalr	t9
+
+	# Return flags are in v0
+	bne     v0, FFI_TYPE_INT, cls_retfloat
+	REG_L	v0, V0_OFF2($sp)
+	b	cls_epilogue
+
+cls_retfloat:
+	bne     v0, FFI_TYPE_FLOAT, cls_retdouble
+	l.s	$f0, V0_OFF2($sp)
+	b	cls_epilogue
+
+cls_retdouble:	
+	bne	v0, FFI_TYPE_DOUBLE, cls_retstruct_d
+	l.d	$f0, V0_OFF2($sp)
+	b	cls_epilogue
+
+cls_retstruct_d:	
+	bne	v0, FFI_TYPE_STRUCT_D, cls_retstruct_f
+	l.d	$f0, V0_OFF2($sp)
+	b	cls_epilogue
+	
+cls_retstruct_f:	
+	bne	v0, FFI_TYPE_STRUCT_F, cls_retstruct_d_d
+	l.s	$f0, V0_OFF2($sp)
+	b	cls_epilogue
+	
+cls_retstruct_d_d:	
+	bne	v0, FFI_TYPE_STRUCT_DD, cls_retstruct_f_f
+	l.d	$f0, V0_OFF2($sp)
+	l.d	$f2, V1_OFF2($sp)
+	b	cls_epilogue
+	
+cls_retstruct_f_f:	
+	bne	v0, FFI_TYPE_STRUCT_FF, cls_retstruct_d_f
+	l.s	$f0, V0_OFF2($sp)
+	l.s	$f2, V1_OFF2($sp)
+	b	cls_epilogue
+	
+cls_retstruct_d_f:	
+	bne	v0, FFI_TYPE_STRUCT_DF, cls_retstruct_f_d
+	l.d	$f0, V0_OFF2($sp)
+	l.s	$f2, V1_OFF2($sp)
+	b	cls_epilogue
+	
+cls_retstruct_f_d:	
+	bne	v0, FFI_TYPE_STRUCT_FD, cls_retstruct_small2
+	l.s	$f0, V0_OFF2($sp)
+	l.d	$f2, V1_OFF2($sp)
+	b	cls_epilogue
+	
+cls_retstruct_small2:	
+	REG_L	v0, V0_OFF2($sp)
+	REG_L	v1, V1_OFF2($sp)
+	
+	# Epilogue
+cls_epilogue:	
+	REG_L	ra,  RA_OFF2($sp)	 # Restore return address
+	.cpreturn
+	ADDU	$sp, SIZEOF_FRAME2
+	j	ra
+.LFE2:	
+	.end	ffi_closure_N32
+
+        .section        .eh_frame,"aw",@progbits
+.Lframe1:
+        .4byte  .LECIE1-.LSCIE1		# length
+.LSCIE1:
+        .4byte  0x0			# CIE
+        .byte   0x1			# Version 1
+        .ascii  "\000"			# Augmentation
+        .uleb128 0x1			# Code alignment 1
+        .sleb128 -4			# Data alignment -4
+        .byte   0x1f			# Return Address $31
+        .byte   0xc			# DW_CFA_def_cfa
+        .uleb128 0x1d			# in $sp
+        .uleb128 0x0			# offset 0
+        .align  EH_FRAME_ALIGN
+.LECIE1:
+
+.LSFDE1:
+        .4byte  .LEFDE1-.LASFDE1	# length.
+.LASFDE1:
+        .4byte  .LASFDE1-.Lframe1	# CIE_pointer.
+        FDE_ADDR_BYTES  .LFB3		# initial_location.
+        FDE_ADDR_BYTES  .LFE3-.LFB3	# address_range.
+        .byte   0x4			# DW_CFA_advance_loc4
+        .4byte  .LCFI0-.LFB3		# to .LCFI0
+        .byte   0xe			# DW_CFA_def_cfa_offset
+        .uleb128 SIZEOF_FRAME		# adjust stack.by SIZEOF_FRAME
+        .byte   0x4			# DW_CFA_advance_loc4
+        .4byte  .LCFI1-.LCFI0		# to .LCFI1
+        .byte   0x9e			# DW_CFA_offset of $fp
+        .uleb128 2*FFI_SIZEOF_ARG/4	# 
+        .byte   0x9f			# DW_CFA_offset of ra
+        .uleb128 1*FFI_SIZEOF_ARG/4	# 
+        .byte   0x4			# DW_CFA_advance_loc4
+        .4byte  .LCFI3-.LCFI1		# to .LCFI3
+        .byte   0xd			# DW_CFA_def_cfa_register
+        .uleb128 0x1e			# in $fp
+        .align  EH_FRAME_ALIGN
+.LEFDE1:
+.LSFDE3:
+	.4byte	.LEFDE3-.LASFDE3	# length
+.LASFDE3:
+	.4byte	.LASFDE3-.Lframe1	# CIE_pointer.
+	FDE_ADDR_BYTES	.LFB2		# initial_location.
+	FDE_ADDR_BYTES	.LFE2-.LFB2	# address_range.
+	.byte	0x4			# DW_CFA_advance_loc4
+	.4byte	.LCFI5-.LFB2		# to .LCFI5
+	.byte	0xe			# DW_CFA_def_cfa_offset
+	.uleb128 SIZEOF_FRAME2		# adjust stack.by SIZEOF_FRAME
+	.byte	0x4			# DW_CFA_advance_loc4
+	.4byte	.LCFI6-.LCFI5		# to .LCFI6
+	.byte	0x9c			# DW_CFA_offset of $gp ($28)
+	.uleb128 (SIZEOF_FRAME2 - GP_OFF2)/4
+	.byte	0x9f			# DW_CFA_offset of ra ($31)
+	.uleb128 (SIZEOF_FRAME2 - RA_OFF2)/4
+	.align	EH_FRAME_ALIGN
+.LEFDE3:
 	
 #endif
Index: src/mips/o32.S
===================================================================
--- src/mips/o32.S	(revision 127010)
+++ src/mips/o32.S	(working copy)
@@ -183,27 +183,30 @@ $LFE0:
 
 
 /* ffi_closure_O32. Expects address of the passed-in ffi_closure
-	in t0. Stores any arguments passed in registers onto the
+	in t4 ($12). Stores any arguments passed in registers onto the
 	stack, then calls ffi_closure_mips_inner_O32, which
 	then decodes them.
 	
 	Stack layout:
 
-	14 - Start of parameters, original sp
-	13 - ra save
-	12 - fp save
-	11 - $16 (s0) save
-	10 - cprestore
-	 9 - return value high (v1)
-	 8 - return value low (v0)
-	 7 - f14 (le high, be low)
-	 6 - f14 (le low, be high)
-	 5 - f12 (le high, be low)
-	 4 - f12 (le low, be high)
-	 3 - Called function a3 save
-	 2 - Called function a2 save
-	 1 - Called function a1 save
-	 0 - Called function a0 save our sp, fp point here
+	 3 - a3 save
+	 2 - a2 save
+	 1 - a1 save
+	 0 - a0 save, original sp
+	-1 - ra save
+	-2 - fp save
+	-3 - $16 (s0) save
+	-4 - cprestore
+	-5 - return value high (v1)
+	-6 - return value low (v0)
+	-7 - f14 (le high, be low)
+	-8 - f14 (le low, be high)
+	-9 - f12 (le high, be low)
+       -10 - f12 (le low, be high)
+       -11 - Called function a3 save
+       -12 - Called function a2 save
+       -13 - Called function a1 save
+       -14 - Called function a0 save, our sp and fp point here
 	 */
 	
 #define SIZEOF_FRAME2	(14 * FFI_SIZEOF_ARG)
@@ -251,7 +254,7 @@ $LCFI7:
 	REG_S	a3, A3_OFF2($fp)
 
 	# Load ABI enum to s0
-	REG_L	$16, 20($8)	# cif pointer follows tramp.
+	REG_L	$16, 20($12)	# cif pointer follows tramp.
 	REG_L	$16, 0($16)	# abi is first member.
 
 	li	$13, 1		# FFI_O32
@@ -263,7 +266,7 @@ $LCFI7:
 1:	
 	# Call ffi_closure_mips_inner_O32 to do the work.
 	la	t9, ffi_closure_mips_inner_O32
-	move	a0, $8	 # Pointer to the ffi_closure
+	move	a0, $12	 # Pointer to the ffi_closure
 	addu	a1, $fp, V0_OFF2
 	addu	a2, $fp, A0_OFF2
 	addu	a3, $fp, FA_0_0_OFF2
Index: src/mips/ffi.c
===================================================================
--- src/mips/ffi.c	(revision 127010)
+++ src/mips/ffi.c	(working copy)
@@ -28,13 +28,19 @@
 
 #include <stdlib.h>
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_DEBUG
+# define FFI_MIPS_STOP_HERE() ffi_stop_here()
+#else
+# define FFI_MIPS_STOP_HERE() do {} while(0)
+#endif
+
+#ifdef FFI_MIPS_N32
 #define FIX_ARGP \
 FFI_ASSERT(argp <= &stack[bytes]); \
 if (argp == &stack[bytes]) \
 { \
   argp = stack; \
-  ffi_stop_here(); \
+  FFI_MIPS_STOP_HERE(); \
 }
 #else
 #define FIX_ARGP 
@@ -54,7 +60,7 @@ static void ffi_prep_args(char *stack, 
   char *argp;
   ffi_type **p_arg;
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   /* If more than 8 double words are used, the remainder go
      on the stack. We reorder stuff on the stack here to 
      support this easily. */
@@ -68,7 +74,7 @@ static void ffi_prep_args(char *stack, 
 
   memset(stack, 0, bytes);
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   if ( ecif->cif->rstruct_flag != 0 )
 #else
   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
@@ -91,7 +97,7 @@ static void ffi_prep_args(char *stack, 
       if (a < sizeof(ffi_arg))
         a = sizeof(ffi_arg);
       
-      if ((a - 1) & (unsigned int) argp)
+      if ((a - 1) & (unsigned long) argp)
 	{
 	  argp = (char *) ALIGN(argp, a);
 	  FIX_ARGP;
@@ -100,9 +106,15 @@ static void ffi_prep_args(char *stack, 
       z = (*p_arg)->size;
       if (z <= sizeof(ffi_arg))
 	{
+          int type = (*p_arg)->type;
 	  z = sizeof(ffi_arg);
 
-	  switch ((*p_arg)->type)
+          /* The size of a pointer depends on the ABI */
+          if (type == FFI_TYPE_POINTER)
+            type =
+              (ecif->cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+
+	  switch (type)
 	    {
 	      case FFI_TYPE_SINT8:
 		*(ffi_arg *)argp = *(SINT8 *)(* p_argv);
@@ -125,7 +137,6 @@ static void ffi_prep_args(char *stack, 
 		break;
 		  
 	      case FFI_TYPE_UINT32:
-	      case FFI_TYPE_POINTER:
 		*(ffi_arg *)argp = *(UINT32 *)(* p_argv);
 		break;
 
@@ -134,8 +145,7 @@ static void ffi_prep_args(char *stack, 
 		*(float *) argp = *(float *)(* p_argv);
 		break;
 
-	      /* Handle small structures.  */
-	      case FFI_TYPE_STRUCT:
+	      /* Handle structures.  */
 	      default:
 		memcpy(argp, *p_argv, (*p_arg)->size);
 		break;
@@ -143,12 +153,12 @@ static void ffi_prep_args(char *stack, 
 	}
       else
 	{
-#if _MIPS_SIM == _ABIO32
+#ifdef FFI_MIPS_O32
 	  memcpy(argp, *p_argv, z);
 #else
 	  {
-	    unsigned end = (unsigned) argp+z;
-	    unsigned cap = (unsigned) stack+bytes;
+	    unsigned long end = (unsigned long) argp + z;
+	    unsigned long cap = (unsigned long) stack + bytes;
 
 	    /* Check if the data will fit within the register space.
 	       Handle it if it doesn't.  */
@@ -157,12 +167,13 @@ static void ffi_prep_args(char *stack, 
 	      memcpy(argp, *p_argv, z);
 	    else
 	      {
-		unsigned portion = end - cap;
+		unsigned long portion = cap - (unsigned long)argp;
 
 		memcpy(argp, *p_argv, portion);
 		argp = stack;
-		memcpy(argp,
-		       (void*)((unsigned)(*p_argv)+portion), z - portion);
+                z -= portion;
+		memcpy(argp, (void*)((unsigned long)(*p_argv) + portion),
+                       z);
 	      }
 	  }
 #endif
@@ -173,7 +184,7 @@ static void ffi_prep_args(char *stack, 
     }
 }
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
 
 /* The n32 spec says that if "a chunk consists solely of a double 
    float field (but not a double, which is part of a union), it
@@ -181,35 +192,41 @@ static void ffi_prep_args(char *stack, 
    passed in an integer register". This code traverses structure
    definitions and generates the appropriate flags. */
 
-unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift)
+static unsigned
+calc_n32_struct_flags(ffi_type *arg, unsigned *loc, unsigned *arg_reg)
 {
   unsigned flags = 0;
   unsigned index = 0;
 
   ffi_type *e;
 
-  while (e = arg->elements[index])
+  while ((e = arg->elements[index]))
     {
+      /* Align this object.  */
+      *loc = ALIGN(*loc, e->alignment);
       if (e->type == FFI_TYPE_DOUBLE)
 	{
-	  flags += (FFI_TYPE_DOUBLE << *shift);
-	  *shift += FFI_FLAG_BITS;
+          /* Already aligned to FFI_SIZEOF_ARG.  */
+          *arg_reg = *loc / FFI_SIZEOF_ARG;
+          if (*arg_reg > 7)
+            break;
+	  flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS));
+          *loc += e->size;
 	}
-      else if (e->type == FFI_TYPE_STRUCT)
-	  flags += calc_n32_struct_flags(e, shift);
       else
-	*shift += FFI_FLAG_BITS;
-
+        *loc += e->size;
       index++;
     }
+  /* Next Argument register at alignment of FFI_SIZEOF_ARG.  */
+  *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
 
   return flags;
 }
 
-unsigned calc_n32_return_struct_flags(ffi_type *arg)
+static unsigned
+calc_n32_return_struct_flags(ffi_type *arg)
 {
   unsigned flags = 0;
-  unsigned index = 0;
   unsigned small = FFI_TYPE_SMALLSTRUCT;
   ffi_type *e;
 
@@ -228,16 +245,16 @@ unsigned calc_n32_return_struct_flags(ff
 
   e = arg->elements[0];
   if (e->type == FFI_TYPE_DOUBLE)
-    flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
+    flags = FFI_TYPE_DOUBLE;
   else if (e->type == FFI_TYPE_FLOAT)
-    flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS;
+    flags = FFI_TYPE_FLOAT;
 
   if (flags && (e = arg->elements[1]))
     {
       if (e->type == FFI_TYPE_DOUBLE)
-	flags += FFI_TYPE_DOUBLE;
+	flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
       else if (e->type == FFI_TYPE_FLOAT)
-	flags += FFI_TYPE_FLOAT;
+	flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS;
       else 
 	return small;
 
@@ -262,7 +279,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
 {
   cif->flags = 0;
 
-#if _MIPS_SIM == _ABIO32
+#ifdef FFI_MIPS_O32
   /* Set the flags necessary for O32 processing.  FFI_O32_SOFT_FLOAT
    * does not have special handling for floating point args.
    */
@@ -350,10 +367,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
     }
 #endif
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
   /* Set the flags necessary for N32 processing */
   {
-    unsigned shift = 0;
+    unsigned arg_reg = 0;
+    unsigned loc = 0;
     unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
     unsigned index = 0;
 
@@ -368,7 +386,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
 	    /* This means that the structure is being passed as
 	       a hidden argument */
 
-	    shift = FFI_FLAG_BITS;
+	    arg_reg = 1;
 	    count = (cif->nargs < 7) ? cif->nargs : 7;
 
 	    cif->rstruct_flag = !0;
@@ -379,23 +397,37 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
     else
       cif->rstruct_flag = 0;
 
-    while (count-- > 0)
+    while (count-- > 0 && arg_reg < 8)
       {
 	switch ((cif->arg_types)[index]->type)
 	  {
 	  case FFI_TYPE_FLOAT:
 	  case FFI_TYPE_DOUBLE:
-	    cif->flags += ((cif->arg_types)[index]->type << shift);
-	    shift += FFI_FLAG_BITS;
+	    cif->flags +=
+              ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS));
+	    arg_reg++;
 	    break;
+          case FFI_TYPE_LONGDOUBLE:
+            /* Align it.  */
+            arg_reg = ALIGN(arg_reg, 2);
+            /* Treat it as two adjacent doubles.  */
+	    cif->flags +=
+              (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+            arg_reg++;
+	    cif->flags +=
+              (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS));
+            arg_reg++;
+            break;
 
 	  case FFI_TYPE_STRUCT:
+            loc = arg_reg * FFI_SIZEOF_ARG;
 	    cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
-						&shift);
+						&loc, &arg_reg);
 	    break;
 
 	  default:
-	    shift += FFI_FLAG_BITS;
+	    arg_reg++;
+            break;
 	  }
 
 	index++;
@@ -430,7 +462,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif 
       case FFI_TYPE_DOUBLE:
 	cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
 	break;
-	
+
       default:
 	cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
 	break;
@@ -469,7 +501,7 @@ void ffi_call(ffi_cif *cif, void (*fn)()
     
   switch (cif->abi) 
     {
-#if _MIPS_SIM == _ABIO32
+#ifdef FFI_MIPS_O32
     case FFI_O32:
     case FFI_O32_SOFT_FLOAT:
       ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, 
@@ -477,10 +509,25 @@ void ffi_call(ffi_cif *cif, void (*fn)()
       break;
 #endif
 
-#if _MIPS_SIM == _ABIN32
+#ifdef FFI_MIPS_N32
     case FFI_N32:
-      ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, 
-		   cif->flags, ecif.rvalue, fn);
+    case FFI_N64:
+      {
+        int copy_rvalue = 0;
+        void *rvalue_copy = ecif.rvalue;
+        if (cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size < 16)
+          {
+            /* For structures smaller than 16 bytes we clobber memory
+               in 8 byte increments.  Make a copy so we don't clobber
+               the callers memory outside of the struct bounds.  */
+            rvalue_copy = alloca(16);
+            copy_rvalue = 1;
+          }
+        ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
+                     cif->flags, rvalue_copy, fn);
+        if (copy_rvalue)
+          memcpy(ecif.rvalue, rvalue_copy, cif->rtype->size);
+      }
       break;
 #endif
 
@@ -490,9 +537,11 @@ void ffi_call(ffi_cif *cif, void (*fn)()
     }
 }
 
-#if FFI_CLOSURES  /* N32 not implemented yet, FFI_CLOSURES not defined */
+#if FFI_CLOSURES
 #if defined(FFI_MIPS_O32)
 extern void ffi_closure_O32(void);
+#else
+extern void ffi_closure_N32(void);
 #endif /* FFI_MIPS_O32 */
 
 ffi_status
@@ -503,23 +552,58 @@ ffi_prep_closure_loc (ffi_closure *closu
 		      void *codeloc)
 {
   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
-  unsigned int fn;
-  unsigned int ctx = (unsigned int) codeloc;
+  void * fn;
   char *clear_location = (char *) codeloc;
 
 #if defined(FFI_MIPS_O32)
   FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT);
-  fn = (unsigned int) ffi_closure_O32;
+  fn = ffi_closure_O32;
 #else /* FFI_MIPS_N32 */
-  FFI_ASSERT(cif->abi == FFI_N32);
-  FFI_ASSERT(!"not implemented");
+  FFI_ASSERT(cif->abi == FFI_N32 || cif->abi == FFI_N64);
+  fn = ffi_closure_N32;
 #endif /* FFI_MIPS_O32 */
 
-  tramp[0] = 0x3c190000 | (fn >> 16);     /* lui  $25,high(fn) */
-  tramp[1] = 0x37390000 | (fn & 0xffff);  /* ori  $25,low(fn)  */
-  tramp[2] = 0x3c080000 | (ctx >> 16);    /* lui  $8,high(ctx) */
-  tramp[3] = 0x03200008;                  /* jr   $25          */
-  tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori  $8,low(ctx)  */
+#if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32)
+  /* lui  $25,high(fn) */
+  tramp[0] = 0x3c190000 | ((unsigned)fn >> 16);
+  /* ori  $25,low(fn)  */
+  tramp[1] = 0x37390000 | ((unsigned)fn & 0xffff);
+  /* lui  $12,high(codeloc) */
+  tramp[2] = 0x3c0c0000 | ((unsigned)codeloc >> 16);
+  /* jr   $25          */
+  tramp[3] = 0x03200008;
+  /* ori  $12,low(codeloc)  */
+  tramp[4] = 0x358c0000 | ((unsigned)codeloc & 0xffff);
+#else
+  /* N64 has a somewhat larger trampoline.  */
+  /* lui  $25,high(fn) */
+  tramp[0] = 0x3c190000 | ((unsigned long)fn >> 48);
+  /* lui  $12,high(codeloc) */
+  tramp[1] = 0x3c0c0000 | ((unsigned long)codeloc >> 48);
+  /* ori  $25,mid-high(fn)  */
+  tramp[2] = 0x37390000 | (((unsigned long)fn >> 32 ) & 0xffff);
+  /* ori  $12,mid-high(codeloc)  */
+  tramp[3] = 0x358c0000 | (((unsigned long)codeloc >> 32) & 0xffff);
+  /* dsll $25,$25,16 */
+  tramp[4] = 0x0019cc38;
+  /* dsll $12,$12,16 */
+  tramp[5] = 0x000c6438;
+  /* ori  $25,mid-low(fn)  */
+  tramp[6] = 0x37390000 | (((unsigned long)fn >> 16 ) & 0xffff);
+  /* ori  $12,mid-low(codeloc)  */
+  tramp[7] = 0x358c0000 | (((unsigned long)codeloc >> 16) & 0xffff);
+  /* dsll $25,$25,16 */
+  tramp[8] = 0x0019cc38;
+  /* dsll $12,$12,16 */
+  tramp[9] = 0x000c6438;
+  /* ori  $25,low(fn)  */
+  tramp[10] = 0x37390000 | ((unsigned long)fn  & 0xffff);
+  /* jr   $25          */
+  tramp[11] = 0x03200008;
+  /* ori  $12,low(codeloc)  */
+  tramp[12] = 0x358c0000 | ((unsigned long)codeloc & 0xffff);
+
+#endif
 
   closure->cif = cif;
   closure->fun = fun;
@@ -567,7 +651,7 @@ ffi_closure_mips_inner_O32 (ffi_closure 
 
   if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
     {
-      rvalue = (void *) ar[0];
+      rvalue = (void *)(UINT32)ar[0];
       argn = 1;
     }
 
@@ -645,4 +729,177 @@ ffi_closure_mips_inner_O32 (ffi_closure 
     }
 }
 
+#if defined(FFI_MIPS_N32)
+
+static void
+copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type,
+                int argn, unsigned arg_offset, ffi_arg *ar,
+                ffi_arg *fpr)
+{
+  ffi_type **elt_typep = type->elements;
+  while(*elt_typep)
+    {
+      ffi_type *elt_type = *elt_typep;
+      unsigned o;
+      char *tp;
+      char *argp;
+      char *fpp;
+
+      o = ALIGN(offset, elt_type->alignment);
+      arg_offset += o - offset;
+      offset = o;
+      argn += arg_offset / sizeof(ffi_arg);
+      arg_offset = arg_offset % sizeof(ffi_arg);
+
+      argp = (char *)(ar + argn);
+      fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn);
+
+      tp = target + offset;
+
+      if (elt_type->type == FFI_TYPE_DOUBLE)
+        *(double *)tp = *(double *)fpp;
+      else
+        memcpy(tp, argp + arg_offset, elt_type->size);
+
+      offset += elt_type->size;
+      arg_offset += elt_type->size;
+      elt_typep++;
+      argn += arg_offset / sizeof(ffi_arg);
+      arg_offset = arg_offset % sizeof(ffi_arg);
+    }
+}
+
+/*
+ * Decodes the arguments to a function, which will be stored on the
+ * stack. AR is the pointer to the beginning of the integer
+ * arguments. FPR is a pointer to the area where floating point
+ * registers have been saved.
+ *
+ * RVALUE is the location where the function return value will be
+ * stored. CLOSURE is the prepared closure to invoke.
+ *
+ * This function should only be called from assembly, which is in
+ * turn called from a trampoline.
+ *
+ * Returns the function return flags.
+ *
+ */
+int
+ffi_closure_mips_inner_N32 (ffi_closure *closure,
+			    void *rvalue, ffi_arg *ar,
+			    ffi_arg *fpr)
+{
+  ffi_cif *cif;
+  void **avaluep;
+  ffi_arg *avalue;
+  ffi_type **arg_types;
+  int i, avn, argn;
+
+  cif = closure->cif;
+  avalue = alloca (cif->nargs * sizeof (ffi_arg));
+  avaluep = alloca (cif->nargs * sizeof (ffi_arg));
+
+  argn = 0;
+
+  if (cif->rstruct_flag)
+    {
+#if _MIPS_SIM==_ABIN32
+      rvalue = (void *)(UINT32)ar[0];
+#else /* N64 */
+      rvalue = (void *)ar[0];
+#endif
+      argn = 1;
+    }
+
+  i = 0;
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
+  while (i < avn)
+    {
+      if (arg_types[i]->type == FFI_TYPE_FLOAT
+          || arg_types[i]->type == FFI_TYPE_DOUBLE)
+        {
+          ffi_arg *argp = argn >= 8 ? ar + argn : fpr + argn;
+#ifdef __MIPSEB__
+          if (arg_types[i]->type == FFI_TYPE_FLOAT && argn < 8)
+            avaluep[i] = ((char *) argp) + sizeof (float);
+          else
+#endif
+            avaluep[i] = (char *) argp;
+        }
+      else
+        {
+          unsigned type = arg_types[i]->type;
+
+          if (arg_types[i]->alignment > sizeof(ffi_arg))
+            argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg));
+
+          ffi_arg *argp = ar + argn;
+
+          /* The size of a pointer depends on the ABI */
+          if (type == FFI_TYPE_POINTER)
+            type = (cif->abi == FFI_N64) ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32;
+
+          switch (type)
+            {
+            case FFI_TYPE_SINT8:
+              avaluep[i] = &avalue[i];
+              *(SINT8 *) &avalue[i] = (SINT8) *argp;
+              break;
+
+            case FFI_TYPE_UINT8:
+              avaluep[i] = &avalue[i];
+              *(UINT8 *) &avalue[i] = (UINT8) *argp;
+              break;
+
+            case FFI_TYPE_SINT16:
+              avaluep[i] = &avalue[i];
+              *(SINT16 *) &avalue[i] = (SINT16) *argp;
+              break;
+
+            case FFI_TYPE_UINT16:
+              avaluep[i] = &avalue[i];
+              *(UINT16 *) &avalue[i] = (UINT16) *argp;
+              break;
+
+            case FFI_TYPE_SINT32:
+              avaluep[i] = &avalue[i];
+              *(SINT32 *) &avalue[i] = (SINT32) *argp;
+              break;
+
+            case FFI_TYPE_UINT32:
+              avaluep[i] = &avalue[i];
+              *(UINT32 *) &avalue[i] = (UINT32) *argp;
+              break;
+
+            case FFI_TYPE_STRUCT:
+              if (argn < 8)
+                {
+                  /* Allocate space for the struct as at least part of
+                     it was passed in registers.  */
+                  avaluep[i] = alloca(arg_types[i]->size);
+                  copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i],
+                                  argn, 0, ar, fpr);
+
+                  break;
+                }
+              /* Else fall through.  */
+            default:
+              avaluep[i] = (char *) argp;
+              break;
+            }
+        }
+      argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg);
+      i++;
+    }
+
+  /* Invoke the closure. */
+  (closure->fun) (cif, rvalue, avaluep, closure->user_data);
+
+  return cif->flags >> (FFI_FLAG_BITS * 8);
+}
+
+#endif /* FFI_MIPS_N32 */
+
 #endif /* FFI_CLOSURES */

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