Add powerpc soft float support

This commit is contained in:
Anthony Green
2011-11-12 16:35:55 -05:00
parent c8f1bde8e2
commit 52891f8a93
17 changed files with 9744 additions and 264 deletions

View File

@@ -34,3 +34,4 @@ kfreebsd-mmap
minix minix
interix-patch interix-patch
remove-debug-code remove-debug-code
powerpc-ffi-softfloat

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,139 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc
Target configuration macros for PowerPC.
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 THE AUTHORS OR COPYRIGHT
HOLDERS 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.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
/* ---- System specific configurations ----------------------------------- */
#if defined (POWERPC) && defined (__powerpc64__) /* linux64 */
#ifndef POWERPC64
#define POWERPC64
#endif
#elif defined (POWERPC_DARWIN) && defined (__ppc64__) /* Darwin64 */
#ifndef POWERPC64
#define POWERPC64
#endif
#ifndef POWERPC_DARWIN64
#define POWERPC_DARWIN64
#endif
#elif defined (POWERPC_AIX) && defined (__64BIT__) /* AIX64 */
#ifndef POWERPC64
#define POWERPC64
#endif
#endif
#ifndef LIBFFI_ASM
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
#ifdef POWERPC
FFI_SYSV,
FFI_GCC_SYSV,
FFI_LINUX64,
FFI_LINUX,
FFI_LINUX_SOFT_FLOAT,
# ifdef POWERPC64
FFI_DEFAULT_ABI = FFI_LINUX64,
# else
# if (!defined(__NO_FPRS__) && (__LDBL_MANT_DIG__ == 106))
FFI_DEFAULT_ABI = FFI_LINUX,
# else
# ifdef __NO_FPRS__
FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT,
# else
FFI_DEFAULT_ABI = FFI_GCC_SYSV,
# endif
# endif
# endif
#endif
#ifdef POWERPC_AIX
FFI_AIX,
FFI_DARWIN,
FFI_DEFAULT_ABI = FFI_AIX,
#endif
#ifdef POWERPC_DARWIN
FFI_AIX,
FFI_DARWIN,
FFI_DEFAULT_ABI = FFI_DARWIN,
#endif
#ifdef POWERPC_FREEBSD
FFI_SYSV,
FFI_GCC_SYSV,
FFI_LINUX64,
FFI_LINUX,
FFI_LINUX_SOFT_FLOAT,
FFI_DEFAULT_ABI = FFI_SYSV,
#endif
FFI_LAST_ABI
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_NATIVE_RAW_API 0
/* For additional types like the below, take care about the order in
ppc_closures.S. They must follow after the FFI_TYPE_LAST. */
/* Needed for soft-float long-double-128 support. */
#define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1)
/* Needed for FFI_SYSV small structure returns.
We use two flag bits, (FLAG_SYSV_SMST_R3, FLAG_SYSV_SMST_R4) which are
defined in ffi.c, to determine the exact return type and its size. */
#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2)
#if defined(POWERPC64) || defined(POWERPC_AIX)
# if defined(POWERPC_DARWIN64)
# define FFI_TRAMPOLINE_SIZE 48
# else
# define FFI_TRAMPOLINE_SIZE 24
# endif
#else /* POWERPC || POWERPC_AIX */
# define FFI_TRAMPOLINE_SIZE 40
#endif
#ifndef LIBFFI_ASM
#if defined(POWERPC_DARWIN) || defined(POWERPC_AIX)
struct ffi_aix_trampoline_struct {
void * code_pointer; /* Pointer to ffi_closure_ASM */
void * toc; /* TOC */
void * static_chain; /* Pointer to closure */
};
#endif
#endif
#endif

View File

@@ -0,0 +1,327 @@
/* -----------------------------------------------------------------------
sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
Copyright (c) 2008 Red Hat, Inc.
PowerPC Assembly glue.
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 THE AUTHORS OR COPYRIGHT
HOLDERS 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 <fficonfig.h>
#include <ffi.h>
#include <powerpc/asm.h>
.file "ppc_closure.S"
#ifndef __powerpc64__
ENTRY(ffi_closure_SYSV)
.LFB1:
stwu %r1,-144(%r1)
.LCFI0:
mflr %r0
.LCFI1:
stw %r0,148(%r1)
# we want to build up an areas for the parameters passed
# in registers (both floating point and integer)
# so first save gpr 3 to gpr 10 (aligned to 4)
stw %r3, 16(%r1)
stw %r4, 20(%r1)
stw %r5, 24(%r1)
stw %r6, 28(%r1)
stw %r7, 32(%r1)
stw %r8, 36(%r1)
stw %r9, 40(%r1)
stw %r10,44(%r1)
#ifndef __NO_FPRS__
# next save fpr 1 to fpr 8 (aligned to 8)
stfd %f1, 48(%r1)
stfd %f2, 56(%r1)
stfd %f3, 64(%r1)
stfd %f4, 72(%r1)
stfd %f5, 80(%r1)
stfd %f6, 88(%r1)
stfd %f7, 96(%r1)
stfd %f8, 104(%r1)
#endif
# set up registers for the routine that actually does the work
# get the context pointer from the trampoline
mr %r3,%r11
# now load up the pointer to the result storage
addi %r4,%r1,112
# now load up the pointer to the saved gpr registers
addi %r5,%r1,16
# now load up the pointer to the saved fpr registers */
addi %r6,%r1,48
# now load up the pointer to the outgoing parameter
# stack in the previous frame
# i.e. the previous frame pointer + 8
addi %r7,%r1,152
# make the call
bl ffi_closure_helper_SYSV@local
.Lret:
# now r3 contains the return type
# so use it to look up in a table
# so we know how to deal with each type
# look up the proper starting point in table
# by using return type as offset
mflr %r4 # move address of .Lret to r4
slwi %r3,%r3,4 # now multiply return type by 16
addi %r4, %r4, .Lret_type0 - .Lret
lwz %r0,148(%r1)
add %r3,%r3,%r4 # add contents of table to table address
mtctr %r3
bctr # jump to it
.LFE1:
# Each of the ret_typeX code fragments has to be exactly 16 bytes long
# (4 instructions). For cache effectiveness we align to a 16 byte boundary
# first.
.align 4
# case FFI_TYPE_VOID
.Lret_type0:
mtlr %r0
addi %r1,%r1,144
blr
nop
# case FFI_TYPE_INT
lwz %r3,112+0(%r1)
mtlr %r0
.Lfinish:
addi %r1,%r1,144
blr
# case FFI_TYPE_FLOAT
lfs %f1,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_DOUBLE
lfd %f1,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_LONGDOUBLE
lfd %f1,112+0(%r1)
lfd %f2,112+8(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_UINT8
lbz %r3,112+3(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT8
lbz %r3,112+3(%r1)
extsb %r3,%r3
mtlr %r0
b .Lfinish
# case FFI_TYPE_UINT16
lhz %r3,112+2(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT16
lha %r3,112+2(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_UINT32
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT32
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_UINT64
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_SINT64
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_STRUCT
mtlr %r0
addi %r1,%r1,144
blr
nop
# case FFI_TYPE_POINTER
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_UINT128
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
lwz %r5,112+8(%r1)
bl .Luint128
# The return types below are only used when the ABI type is FFI_SYSV.
# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
lbz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
lhz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
lwz %r3,112+0(%r1)
srwi %r3,%r3,8
mtlr %r0
b .Lfinish
# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,24
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,16
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,8
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
.Lstruct567:
subfic %r6,%r5,32
srw %r4,%r4,%r5
slw %r6,%r3,%r6
srw %r3,%r3,%r5
or %r4,%r6,%r4
mtlr %r0
addi %r1,%r1,144
blr
.Luint128:
lwz %r6,112+12(%r1)
mtlr %r0
addi %r1,%r1,144
blr
END(ffi_closure_SYSV)
.section ".eh_frame",EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 # Length of Common Information Entry
.LSCIE1:
.4byte 0x0 # CIE Identifier Tag
.byte 0x1 # CIE Version
#if defined _RELOCATABLE || defined __PIC__
.ascii "zR\0" # CIE Augmentation
#else
.ascii "\0" # CIE Augmentation
#endif
.uleb128 0x1 # CIE Code Alignment Factor
.sleb128 -4 # CIE Data Alignment Factor
.byte 0x41 # CIE RA Column
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x1 # Augmentation size
.byte 0x1b # FDE Encoding (pcrel sdata4)
#endif
.byte 0xc # DW_CFA_def_cfa
.uleb128 0x1
.uleb128 0x0
.align 2
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 # FDE Length
.LASFDE1:
.4byte .LASFDE1-.Lframe1 # FDE CIE offset
#if defined _RELOCATABLE || defined __PIC__
.4byte .LFB1-. # FDE initial location
#else
.4byte .LFB1 # FDE initial location
#endif
.4byte .LFE1-.LFB1 # FDE address range
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x0 # Augmentation size
#endif
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI0-.LFB1
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 144
.byte 0x4 # DW_CFA_advance_loc4
.4byte .LCFI1-.LCFI0
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x41
.sleb128 -1
.align 2
.LEFDE1:
#endif
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif

View File

@@ -0,0 +1,214 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 1998 Geoffrey Keating
Copyright (C) 2007 Free Software Foundation, Inc
PowerPC Assembly glue.
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 THE AUTHORS OR COPYRIGHT
HOLDERS 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 <fficonfig.h>
#include <ffi.h>
#include <powerpc/asm.h>
#ifndef __powerpc64__
.globl ffi_prep_args_SYSV
ENTRY(ffi_call_SYSV)
.LFB1:
/* Save the old stack pointer as AP. */
mr %r8,%r1
.LCFI0:
/* Allocate the stack space we need. */
stwux %r1,%r1,%r4
/* Save registers we use. */
mflr %r9
stw %r28,-16(%r8)
.LCFI1:
stw %r29,-12(%r8)
.LCFI2:
stw %r30, -8(%r8)
.LCFI3:
stw %r31, -4(%r8)
.LCFI4:
stw %r9, 4(%r8)
.LCFI5:
/* Save arguments over call... */
mr %r31,%r5 /* flags, */
mr %r30,%r6 /* rvalue, */
mr %r29,%r7 /* function address, */
mr %r28,%r8 /* our AP. */
.LCFI6:
/* Call ffi_prep_args_SYSV. */
mr %r4,%r1
bl ffi_prep_args_SYSV@local
/* Now do the call. */
/* Set up cr1 with bits 4-7 of the flags. */
mtcrf 0x40,%r31
/* Get the address to call into CTR. */
mtctr %r29
/* Load all those argument registers. */
lwz %r3,-16-(8*4)(%r28)
lwz %r4,-16-(7*4)(%r28)
lwz %r5,-16-(6*4)(%r28)
lwz %r6,-16-(5*4)(%r28)
bf- 5,1f
nop
lwz %r7,-16-(4*4)(%r28)
lwz %r8,-16-(3*4)(%r28)
lwz %r9,-16-(2*4)(%r28)
lwz %r10,-16-(1*4)(%r28)
nop
1:
/* Load all the FP registers. */
bf- 6,2f
lfd %f1,-16-(8*4)-(8*8)(%r28)
lfd %f2,-16-(8*4)-(7*8)(%r28)
lfd %f3,-16-(8*4)-(6*8)(%r28)
lfd %f4,-16-(8*4)-(5*8)(%r28)
nop
lfd %f5,-16-(8*4)-(4*8)(%r28)
lfd %f6,-16-(8*4)-(3*8)(%r28)
lfd %f7,-16-(8*4)-(2*8)(%r28)
lfd %f8,-16-(8*4)-(1*8)(%r28)
2:
/* Make the call. */
bctrl
/* Now, deal with the return value. */
mtcrf 0x01,%r31 /* cr7 */
bt- 31,L(small_struct_return_value)
bt- 30,L(done_return_value)
bt- 29,L(fp_return_value)
stw %r3,0(%r30)
bf+ 28,L(done_return_value)
stw %r4,4(%r30)
mtcrf 0x02,%r31 /* cr6 */
bf 27,L(done_return_value)
stw %r5,8(%r30)
stw %r6,12(%r30)
/* Fall through... */
L(done_return_value):
/* Restore the registers we used and return. */
lwz %r9, 4(%r28)
lwz %r31, -4(%r28)
mtlr %r9
lwz %r30, -8(%r28)
lwz %r29,-12(%r28)
lwz %r28,-16(%r28)
lwz %r1,0(%r1)
blr
L(fp_return_value):
bf 28,L(float_return_value)
stfd %f1,0(%r30)
mtcrf 0x02,%r31 /* cr6 */
bf 27,L(done_return_value)
stfd %f2,8(%r30)
b L(done_return_value)
L(float_return_value):
stfs %f1,0(%r30)
b L(done_return_value)
L(small_struct_return_value):
/*
* The C code always allocates a properly-aligned 8-byte bounce
* buffer to make this assembly code very simple. Just write out
* r3 and r4 to the buffer to allow the C code to handle the rest.
*/
stw %r3, 0(%r30)
stw %r4, 4(%r30)
b L(done_return_value)
.LFE1:
END(ffi_call_SYSV)
.section ".eh_frame",EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
.LSCIE1:
.4byte 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
#if defined _RELOCATABLE || defined __PIC__
.ascii "zR\0" /* CIE Augmentation */
#else
.ascii "\0" /* CIE Augmentation */
#endif
.uleb128 0x1 /* CIE Code Alignment Factor */
.sleb128 -4 /* CIE Data Alignment Factor */
.byte 0x41 /* CIE RA Column */
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x1 /* Augmentation size */
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
#endif
.byte 0xc /* DW_CFA_def_cfa */
.uleb128 0x1
.uleb128 0x0
.align 2
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1:
.4byte .LASFDE1-.Lframe1 /* FDE CIE offset */
#if defined _RELOCATABLE || defined __PIC__
.4byte .LFB1-. /* FDE initial location */
#else
.4byte .LFB1 /* FDE initial location */
#endif
.4byte .LFE1-.LFB1 /* FDE address range */
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x0 /* Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI0-.LFB1
.byte 0xd /* DW_CFA_def_cfa_register */
.uleb128 0x08
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI5-.LCFI0
.byte 0x11 /* DW_CFA_offset_extended_sf */
.uleb128 0x41
.sleb128 -1
.byte 0x9f /* DW_CFA_offset, column 0x1f */
.uleb128 0x1
.byte 0x9e /* DW_CFA_offset, column 0x1e */
.uleb128 0x2
.byte 0x9d /* DW_CFA_offset, column 0x1d */
.uleb128 0x3
.byte 0x9c /* DW_CFA_offset, column 0x1c */
.uleb128 0x4
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI6-.LCFI5
.byte 0xd /* DW_CFA_def_cfa_register */
.uleb128 0x1c
.align 2
.LEFDE1:
#endif
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif

View File

@@ -1,3 +1,9 @@
2011-11-12 Kyle Moffett <Kyle.D.Moffett@boeing.com>
* src/powerpc/ffi.c, src/powerpc/ffitarget.h,
src/powerpc/ppc_closure.S, src/powerpc/sysv.S: Many changes for
softfloat powerpc variants.
2011-11-12 Petr Salinger <Petr.Salinger@seznam.cz> 2011-11-12 Petr Salinger <Petr.Salinger@seznam.cz>
* configure.ac (FFI_EXEC_TRAMPOLINE_TABLE): Fix kfreebsd support. * configure.ac (FFI_EXEC_TRAMPOLINE_TABLE): Fix kfreebsd support.

View File

@@ -0,0 +1,970 @@
Index: libffi/ChangeLog
===================================================================
--- libffi.orig/ChangeLog
+++ libffi/ChangeLog
@@ -1,3 +1,9 @@
+2011-11-12 Kyle Moffett <Kyle.D.Moffett@boeing.com>
+
+ * src/powerpc/ffi.c, src/powerpc/ffitarget.h,
+ src/powerpc/ppc_closure.S, src/powerpc/sysv.S: Many changes for
+ softfloat powerpc variants.
+
2011-11-12 Petr Salinger <Petr.Salinger@seznam.cz>
* configure.ac (FFI_EXEC_TRAMPOLINE_TABLE): Fix kfreebsd support.
@@ -17,7 +23,7 @@
2011-11-12 Kimura Wataru <kimuraw@i.nifty.jp>
* m4/ax_enable_builddir: Change from string comparison to numeric
- comparison for wc output.
+ comparison for wc output.
* configure.ac: Enable FFI_MMAP_EXEC_WRIT for darwin11 aka Mac OS
X 10.7.
* configure: Rebuilt.
Index: libffi/src/powerpc/ffi.c
===================================================================
--- libffi.orig/src/powerpc/ffi.c
+++ libffi/src/powerpc/ffi.c
@@ -41,27 +41,28 @@ enum {
/* The assembly depends on these exact flags. */
FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
+#ifndef __NO_FPRS__
FLAG_RETURNS_FP = 1 << (31-29),
+#endif
FLAG_RETURNS_64BITS = 1 << (31-28),
FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */
FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
+#ifndef __NO_FPRS__
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
+#endif
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
FLAG_RETVAL_REFERENCE = 1 << (31- 4)
};
/* About the SYSV ABI. */
-unsigned int NUM_GPR_ARG_REGISTERS = 8;
+#define ASM_NEEDS_REGISTERS 4
+#define NUM_GPR_ARG_REGISTERS 8
#ifndef __NO_FPRS__
-unsigned int NUM_FPR_ARG_REGISTERS = 8;
-#else
-unsigned int NUM_FPR_ARG_REGISTERS = 0;
+# define NUM_FPR_ARG_REGISTERS 8
#endif
-enum { ASM_NEEDS_REGISTERS = 4 };
-
/* ffi_prep_args_SYSV is called by the assembly routine once stack space
has been allocated for the function's arguments.
@@ -110,10 +111,12 @@ ffi_prep_args_SYSV (extended_cif *ecif,
valp gpr_base;
int intarg_count;
+#ifndef __NO_FPRS__
/* 'fpr_base' points at the space for fpr1, and grows upwards as
we use FPR registers. */
valp fpr_base;
int fparg_count;
+#endif
/* 'copy_space' grows down as we put structures in it. It should
stay 16-byte aligned. */
@@ -122,9 +125,8 @@ ffi_prep_args_SYSV (extended_cif *ecif,
/* 'next_arg' grows up as we put parameters in it. */
valp next_arg;
- int i, ii MAYBE_UNUSED;
+ int i;
ffi_type **ptr;
- double double_tmp;
union {
void **v;
char **c;
@@ -140,15 +142,16 @@ ffi_prep_args_SYSV (extended_cif *ecif,
size_t struct_copy_size;
unsigned gprvalue;
- if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
- NUM_FPR_ARG_REGISTERS = 0;
-
stacktop.c = (char *) stack + bytes;
gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
intarg_count = 0;
+#ifndef __NO_FPRS__
fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
fparg_count = 0;
copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
+#else
+ copy_space.c = gpr_base.c;
+#endif
next_arg.u = stack + 2;
/* Check that everything starts aligned properly. */
@@ -171,12 +174,28 @@ ffi_prep_args_SYSV (extended_cif *ecif,
i > 0;
i--, ptr++, p_argv.v++)
{
- switch ((*ptr)->type)
- {
+ unsigned short typenum = (*ptr)->type;
+
+ /* We may need to handle some values depending on ABI */
+ if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) {
+ if (typenum == FFI_TYPE_FLOAT)
+ typenum = FFI_TYPE_UINT32;
+ if (typenum == FFI_TYPE_DOUBLE)
+ typenum = FFI_TYPE_UINT64;
+ if (typenum == FFI_TYPE_LONGDOUBLE)
+ typenum = FFI_TYPE_UINT128;
+ } else if (ecif->cif->abi != FFI_LINUX) {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (typenum == FFI_TYPE_LONGDOUBLE)
+ typenum = FFI_TYPE_STRUCT;
+#endif
+ }
+
+ /* Now test the translated value */
+ switch (typenum) {
+#ifndef __NO_FPRS__
case FFI_TYPE_FLOAT:
/* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
- if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
- goto soft_float_prep;
double_tmp = **p_argv.f;
if (fparg_count >= NUM_FPR_ARG_REGISTERS)
{
@@ -215,43 +234,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
- if ((ecif->cif->abi != FFI_LINUX)
- && (ecif->cif->abi != FFI_LINUX_SOFT_FLOAT))
- goto do_struct;
- /* The soft float ABI for long doubles works like this,
- a long double is passed in four consecutive gprs if available.
- A maximum of 2 long doubles can be passed in gprs.
- If we do not have 4 gprs left, the long double is passed on the
- stack, 4-byte aligned. */
- if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
- {
- unsigned int int_tmp = (*p_argv.ui)[0];
- if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
- {
- if (intarg_count < NUM_GPR_ARG_REGISTERS)
- intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
- *next_arg.u = int_tmp;
- next_arg.u++;
- for (ii = 1; ii < 4; ii++)
- {
- int_tmp = (*p_argv.ui)[ii];
- *next_arg.u = int_tmp;
- next_arg.u++;
- }
- }
- else
- {
- *gpr_base.u++ = int_tmp;
- for (ii = 1; ii < 4; ii++)
- {
- int_tmp = (*p_argv.ui)[ii];
- *gpr_base.u++ = int_tmp;
- }
- }
- intarg_count +=4;
- }
- else
- {
double_tmp = (*p_argv.d)[0];
if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
@@ -277,13 +259,40 @@ ffi_prep_args_SYSV (extended_cif *ecif,
fparg_count += 2;
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
- }
break;
#endif
+#endif /* have FPRs */
+
+ /*
+ * The soft float ABI for long doubles works like this, a long double
+ * is passed in four consecutive GPRs if available. A maximum of 2
+ * long doubles can be passed in gprs. If we do not have 4 GPRs
+ * left, the long double is passed on the stack, 4-byte aligned.
+ */
+ case FFI_TYPE_UINT128: {
+ unsigned int int_tmp = (*p_argv.ui)[0];
+ unsigned int ii;
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3) {
+ if (intarg_count < NUM_GPR_ARG_REGISTERS)
+ intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
+ *(next_arg.u++) = int_tmp;
+ for (ii = 1; ii < 4; ii++) {
+ int_tmp = (*p_argv.ui)[ii];
+ *(next_arg.u++) = int_tmp;
+ }
+ } else {
+ *(gpr_base.u++) = int_tmp;
+ for (ii = 1; ii < 4; ii++) {
+ int_tmp = (*p_argv.ui)[ii];
+ *(gpr_base.u++) = int_tmp;
+ }
+ }
+ intarg_count += 4;
+ break;
+ }
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
- soft_double_prep:
if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
intarg_count++;
if (intarg_count >= NUM_GPR_ARG_REGISTERS)
@@ -316,9 +325,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
break;
case FFI_TYPE_STRUCT:
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- do_struct:
-#endif
struct_copy_size = ((*ptr)->size + 15) & ~0xF;
copy_space.c -= struct_copy_size;
memcpy (copy_space.c, *p_argv.c, (*ptr)->size);
@@ -346,7 +352,6 @@ ffi_prep_args_SYSV (extended_cif *ecif,
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER:
- soft_float_prep:
gprvalue = **p_argv.ui;
@@ -363,8 +368,10 @@ ffi_prep_args_SYSV (extended_cif *ecif,
/* Check that we didn't overrun the stack... */
FFI_ASSERT (copy_space.c >= next_arg.c);
FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
+#ifndef __NO_FPRS__
FFI_ASSERT (fpr_base.u
<= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
+#endif
FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
}
@@ -601,9 +608,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
unsigned type = cif->rtype->type;
unsigned size = cif->rtype->size;
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
- NUM_FPR_ARG_REGISTERS = 0;
-
if (cif->abi != FFI_LINUX64)
{
/* All the machine-independent calculation of cif->bytes will be wrong.
@@ -643,25 +647,38 @@ ffi_prep_cif_machdep (ffi_cif *cif)
- Single/double FP values in fpr1, long double in fpr1,fpr2.
- soft-float float/doubles are treated as UINT32/UINT64 respectivley.
- soft-float long doubles are returned in gpr3-gpr6. */
+ /* First translate for softfloat/nonlinux */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
+ if (type == FFI_TYPE_FLOAT)
+ type = FFI_TYPE_UINT32;
+ if (type == FFI_TYPE_DOUBLE)
+ type = FFI_TYPE_UINT64;
+ if (type == FFI_TYPE_LONGDOUBLE)
+ type = FFI_TYPE_UINT128;
+ } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (type == FFI_TYPE_LONGDOUBLE)
+ type = FFI_TYPE_STRUCT;
+#endif
+ }
+
switch (type)
{
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+#ifndef __NO_FPRS__
case FFI_TYPE_LONGDOUBLE:
- if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64
- && cif->abi != FFI_LINUX_SOFT_FLOAT)
- goto byref;
flags |= FLAG_RETURNS_128BITS;
/* Fall through. */
-#endif
case FFI_TYPE_DOUBLE:
flags |= FLAG_RETURNS_64BITS;
/* Fall through. */
case FFI_TYPE_FLOAT:
- /* With FFI_LINUX_SOFT_FLOAT no fp registers are used. */
- if (cif->abi != FFI_LINUX_SOFT_FLOAT)
- flags |= FLAG_RETURNS_FP;
+ flags |= FLAG_RETURNS_FP;
break;
+#endif
+ case FFI_TYPE_UINT128:
+ flags |= FLAG_RETURNS_128BITS;
+ /* Fall through. */
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
flags |= FLAG_RETURNS_64BITS;
@@ -680,10 +697,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
*/
if (cif->abi == FFI_SYSV && size <= 8)
flags |= FLAG_RETURNS_SMST;
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- byref:
-#endif
intarg_count++;
flags |= FLAG_RETVAL_REFERENCE;
/* Fall through. */
@@ -704,39 +717,36 @@ ffi_prep_cif_machdep (ffi_cif *cif)
Stuff on the stack needs to keep proper alignment. */
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
- switch ((*ptr)->type)
- {
+ unsigned short typenum = (*ptr)->type;
+
+ /* We may need to handle some values depending on ABI */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
+ if (typenum == FFI_TYPE_FLOAT)
+ typenum = FFI_TYPE_UINT32;
+ if (typenum == FFI_TYPE_DOUBLE)
+ typenum = FFI_TYPE_UINT64;
+ if (typenum == FFI_TYPE_LONGDOUBLE)
+ typenum = FFI_TYPE_UINT128;
+ } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (typenum == FFI_TYPE_LONGDOUBLE)
+ typenum = FFI_TYPE_STRUCT;
+#endif
+ }
+
+ switch (typenum) {
+#ifndef __NO_FPRS__
case FFI_TYPE_FLOAT:
- /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
- goto soft_float_cif;
fparg_count++;
/* floating singles are not 8-aligned on stack */
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
- if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
- goto do_struct;
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
- {
- if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
- || intarg_count < NUM_GPR_ARG_REGISTERS)
- /* A long double in FFI_LINUX_SOFT_FLOAT can use only
- a set of four consecutive gprs. If we have not enough,
- we have to adjust the intarg_count value. */
- intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
- intarg_count += 4;
- break;
- }
- else
- fparg_count++;
+ fparg_count++;
/* Fall thru */
#endif
case FFI_TYPE_DOUBLE:
- /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
- goto soft_double_cif;
fparg_count++;
/* If this FP arg is going on the stack, it must be
8-byte-aligned. */
@@ -745,10 +755,21 @@ ffi_prep_cif_machdep (ffi_cif *cif)
&& intarg_count % 2 != 0)
intarg_count++;
break;
+#endif
+ case FFI_TYPE_UINT128:
+ /*
+ * A long double in FFI_LINUX_SOFT_FLOAT can use only a set
+ * of four consecutive gprs. If we do not have enough, we
+ * have to adjust the intarg_count value.
+ */
+ if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
+ && intarg_count < NUM_GPR_ARG_REGISTERS)
+ intarg_count = NUM_GPR_ARG_REGISTERS;
+ intarg_count += 4;
+ break;
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
- soft_double_cif:
/* 'long long' arguments are passed as two words, but
either both words must fit in registers or both go
on the stack. If they go on the stack, they must
@@ -765,9 +786,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
break;
case FFI_TYPE_STRUCT:
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- do_struct:
-#endif
/* We must allocate space for a copy of these to enforce
pass-by-value. Pad the space up to a multiple of 16
bytes (the maximum alignment required for anything under
@@ -775,12 +793,20 @@ ffi_prep_cif_machdep (ffi_cif *cif)
struct_copy_size += ((*ptr)->size + 15) & ~0xF;
/* Fall through (allocate space for the pointer). */
- default:
- soft_float_cif:
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
/* Everything else is passed as a 4-byte word in a GPR, either
the object itself or a pointer to it. */
intarg_count++;
break;
+ default:
+ FFI_ASSERT (0);
}
}
else
@@ -809,16 +835,29 @@ ffi_prep_cif_machdep (ffi_cif *cif)
intarg_count += ((*ptr)->size + 7) / 8;
break;
- default:
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
/* Everything else is passed as a 8-byte word in a GPR, either
the object itself or a pointer to it. */
intarg_count++;
break;
+ default:
+ FFI_ASSERT (0);
}
}
+#ifndef __NO_FPRS__
if (fparg_count != 0)
flags |= FLAG_FP_ARGUMENTS;
+#endif
if (intarg_count > 4)
flags |= FLAG_4_GPR_ARGUMENTS;
if (struct_copy_size != 0)
@@ -826,21 +865,27 @@ ffi_prep_cif_machdep (ffi_cif *cif)
if (cif->abi != FFI_LINUX64)
{
+#ifndef __NO_FPRS__
/* Space for the FPR registers, if needed. */
if (fparg_count != 0)
bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
+#endif
/* Stack space. */
if (intarg_count > NUM_GPR_ARG_REGISTERS)
bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int);
+#ifndef __NO_FPRS__
if (fparg_count > NUM_FPR_ARG_REGISTERS)
bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double);
+#endif
}
else
{
+#ifndef __NO_FPRS__
/* Space for the FPR registers, if needed. */
if (fparg_count != 0)
bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
+#endif
/* Stack space. */
if (intarg_count > NUM_GPR_ARG_REGISTERS64)
@@ -898,9 +943,11 @@ ffi_call(ffi_cif *cif, void (*fn)(void),
switch (cif->abi)
{
#ifndef POWERPC64
+# ifndef __NO_FPRS__
case FFI_SYSV:
case FFI_GCC_SYSV:
case FFI_LINUX:
+# endif
case FFI_LINUX_SOFT_FLOAT:
ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
break;
@@ -1013,32 +1060,38 @@ ffi_closure_helper_SYSV (ffi_closure *cl
void ** avalue;
ffi_type ** arg_types;
long i, avn;
- long nf; /* number of floating registers already used */
- long ng; /* number of general registers already used */
- ffi_cif * cif;
- double temp;
- unsigned size;
+#ifndef __NO_FPRS__
+ long nf = 0; /* number of floating registers already used */
+#endif
+ long ng = 0; /* number of general registers already used */
+
+ ffi_cif *cif = closure->cif;
+ unsigned size = cif->rtype->size;
+ unsigned short rtypenum = cif->rtype->type;
- cif = closure->cif;
avalue = alloca (cif->nargs * sizeof (void *));
- size = cif->rtype->size;
- nf = 0;
- ng = 0;
+ /* First translate for softfloat/nonlinux */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
+ if (rtypenum == FFI_TYPE_FLOAT)
+ rtypenum = FFI_TYPE_UINT32;
+ if (rtypenum == FFI_TYPE_DOUBLE)
+ rtypenum = FFI_TYPE_UINT64;
+ if (rtypenum == FFI_TYPE_LONGDOUBLE)
+ rtypenum = FFI_TYPE_UINT128;
+ } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (rtypenum == FFI_TYPE_LONGDOUBLE)
+ rtypenum = FFI_TYPE_STRUCT;
+#endif
+ }
+
/* Copy the caller's structure return value address so that the closure
returns the data directly to the caller.
For FFI_SYSV the result is passed in r3/r4 if the struct size is less
or equal 8 bytes. */
-
- if ((cif->rtype->type == FFI_TYPE_STRUCT
- && !((cif->abi == FFI_SYSV) && (size <= 8)))
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
- && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
-#endif
- )
- {
+ if (rtypenum == FFI_TYPE_STRUCT && ((cif->abi != FFI_SYSV) || (size > 8))) {
rvalue = (void *) *pgr;
ng++;
pgr++;
@@ -1049,10 +1102,109 @@ ffi_closure_helper_SYSV (ffi_closure *cl
arg_types = cif->arg_types;
/* Grab the addresses of the arguments from the stack frame. */
- while (i < avn)
- {
- switch (arg_types[i]->type)
- {
+ while (i < avn) {
+ unsigned short typenum = arg_types[i]->type;
+
+ /* We may need to handle some values depending on ABI */
+ if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
+ if (typenum == FFI_TYPE_FLOAT)
+ typenum = FFI_TYPE_UINT32;
+ if (typenum == FFI_TYPE_DOUBLE)
+ typenum = FFI_TYPE_UINT64;
+ if (typenum == FFI_TYPE_LONGDOUBLE)
+ typenum = FFI_TYPE_UINT128;
+ } else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ if (typenum == FFI_TYPE_LONGDOUBLE)
+ typenum = FFI_TYPE_STRUCT;
+#endif
+ }
+
+ switch (typenum) {
+#ifndef __NO_FPRS__
+ case FFI_TYPE_FLOAT:
+ /* unfortunately float values are stored as doubles
+ * in the ffi_closure_SYSV code (since we don't check
+ * the type in that routine).
+ */
+
+ /* there are 8 64bit floating point registers */
+
+ if (nf < 8)
+ {
+ temp = pfr->d;
+ pfr->f = (float) temp;
+ avalue[i] = pfr;
+ nf++;
+ pfr++;
+ }
+ else
+ {
+ /* FIXME? here we are really changing the values
+ * stored in the original calling routines outgoing
+ * parameter stack. This is probably a really
+ * naughty thing to do but...
+ */
+ avalue[i] = pst;
+ pst += 1;
+ }
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ /* On the outgoing stack all values are aligned to 8 */
+ /* there are 8 64bit floating point registers */
+
+ if (nf < 8)
+ {
+ avalue[i] = pfr;
+ nf++;
+ pfr++;
+ }
+ else
+ {
+ if (((long) pst) & 4)
+ pst++;
+ avalue[i] = pst;
+ pst += 2;
+ }
+ break;
+
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ if (nf < 7)
+ {
+ avalue[i] = pfr;
+ pfr += 2;
+ nf += 2;
+ }
+ else
+ {
+ if (((long) pst) & 4)
+ pst++;
+ avalue[i] = pst;
+ pst += 4;
+ nf = 8;
+ }
+ break;
+#endif
+#endif /* have FPRS */
+
+ case FFI_TYPE_UINT128:
+ /*
+ * Test if for the whole long double, 4 gprs are available.
+ * otherwise the stuff ends up on the stack.
+ */
+ if (ng < 5) {
+ avalue[i] = pgr;
+ pgr += 4;
+ ng += 4;
+ } else {
+ avalue[i] = pst;
+ pst += 4;
+ ng = 8+4;
+ }
+ break;
+
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
/* there are 8 gpr registers used to pass values */
@@ -1088,7 +1240,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_POINTER:
- soft_float_closure:
/* there are 8 gpr registers used to pass values */
if (ng < 8)
{
@@ -1104,9 +1255,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
break;
case FFI_TYPE_STRUCT:
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- do_struct:
-#endif
/* Structs are passed by reference. The address will appear in a
gpr if it is one of the first 8 arguments. */
if (ng < 8)
@@ -1124,7 +1272,6 @@ ffi_closure_helper_SYSV (ffi_closure *cl
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
- soft_double_closure:
/* passing long long ints are complex, they must
* be passed in suitable register pairs such as
* (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
@@ -1156,99 +1303,8 @@ ffi_closure_helper_SYSV (ffi_closure *cl
}
break;
- case FFI_TYPE_FLOAT:
- /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
- goto soft_float_closure;
- /* unfortunately float values are stored as doubles
- * in the ffi_closure_SYSV code (since we don't check
- * the type in that routine).
- */
-
- /* there are 8 64bit floating point registers */
-
- if (nf < 8)
- {
- temp = pfr->d;
- pfr->f = (float) temp;
- avalue[i] = pfr;
- nf++;
- pfr++;
- }
- else
- {
- /* FIXME? here we are really changing the values
- * stored in the original calling routines outgoing
- * parameter stack. This is probably a really
- * naughty thing to do but...
- */
- avalue[i] = pst;
- pst += 1;
- }
- break;
-
- case FFI_TYPE_DOUBLE:
- /* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
- goto soft_double_closure;
- /* On the outgoing stack all values are aligned to 8 */
- /* there are 8 64bit floating point registers */
-
- if (nf < 8)
- {
- avalue[i] = pfr;
- nf++;
- pfr++;
- }
- else
- {
- if (((long) pst) & 4)
- pst++;
- avalue[i] = pst;
- pst += 2;
- }
- break;
-
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
- if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
- goto do_struct;
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
- { /* Test if for the whole long double, 4 gprs are available.
- otherwise the stuff ends up on the stack. */
- if (ng < 5)
- {
- avalue[i] = pgr;
- pgr += 4;
- ng += 4;
- }
- else
- {
- avalue[i] = pst;
- pst += 4;
- ng = 8;
- }
- break;
- }
- if (nf < 7)
- {
- avalue[i] = pfr;
- pfr += 2;
- nf += 2;
- }
- else
- {
- if (((long) pst) & 4)
- pst++;
- avalue[i] = pst;
- pst += 4;
- nf = 8;
- }
- break;
-#endif
-
default:
- FFI_ASSERT (0);
+ FFI_ASSERT (0);
}
i++;
@@ -1265,39 +1321,9 @@ ffi_closure_helper_SYSV (ffi_closure *cl
already used and we never have a struct with size zero. That is the reason
for the subtraction of 1. See the comment in ffitarget.h about ordering.
*/
- if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
- && size <= 8)
+ if (cif->abi == FFI_SYSV && rtypenum == FFI_TYPE_STRUCT && size <= 8)
return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size;
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
- && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
- return FFI_TYPE_STRUCT;
-#endif
- /* With FFI_LINUX_SOFT_FLOAT floats and doubles are handled like UINT32
- respectivley UINT64. */
- if (cif->abi == FFI_LINUX_SOFT_FLOAT)
- {
- switch (cif->rtype->type)
- {
- case FFI_TYPE_FLOAT:
- return FFI_TYPE_UINT32;
- break;
- case FFI_TYPE_DOUBLE:
- return FFI_TYPE_UINT64;
- break;
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- case FFI_TYPE_LONGDOUBLE:
- return FFI_TYPE_UINT128;
- break;
-#endif
- default:
- return cif->rtype->type;
- }
- }
- else
- {
- return cif->rtype->type;
- }
+ return rtypenum;
}
int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,
Index: libffi/src/powerpc/ffitarget.h
===================================================================
--- libffi.orig/src/powerpc/ffitarget.h
+++ libffi/src/powerpc/ffitarget.h
@@ -60,18 +60,14 @@ typedef enum ffi_abi {
FFI_LINUX64,
FFI_LINUX,
FFI_LINUX_SOFT_FLOAT,
-# ifdef POWERPC64
+# if defined(POWERPC64)
FFI_DEFAULT_ABI = FFI_LINUX64,
-# else
-# if (!defined(__NO_FPRS__) && (__LDBL_MANT_DIG__ == 106))
- FFI_DEFAULT_ABI = FFI_LINUX,
-# else
-# ifdef __NO_FPRS__
+# elif defined(__NO_FPRS__)
FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT,
-# else
+# elif (__LDBL_MANT_DIG__ == 106)
+ FFI_DEFAULT_ABI = FFI_LINUX,
+# else
FFI_DEFAULT_ABI = FFI_GCC_SYSV,
-# endif
-# endif
# endif
#endif
Index: libffi/src/powerpc/ppc_closure.S
===================================================================
--- libffi.orig/src/powerpc/ppc_closure.S
+++ libffi/src/powerpc/ppc_closure.S
@@ -122,22 +122,41 @@ ENTRY(ffi_closure_SYSV)
blr
# case FFI_TYPE_FLOAT
+#ifndef __NO_FPRS__
lfs %f1,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
+#else
+ nop
+ nop
+ nop
+#endif
blr
# case FFI_TYPE_DOUBLE
+#ifndef __NO_FPRS__
lfd %f1,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
+#else
+ nop
+ nop
+ nop
+#endif
blr
# case FFI_TYPE_LONGDOUBLE
+#ifndef __NO_FPRS__
lfd %f1,112+0(%r1)
lfd %f2,112+8(%r1)
mtlr %r0
b .Lfinish
+#else
+ nop
+ nop
+ nop
+ blr
+#endif
# case FFI_TYPE_UINT8
lbz %r3,112+3(%r1)
Index: libffi/src/powerpc/sysv.S
===================================================================
--- libffi.orig/src/powerpc/sysv.S
+++ libffi/src/powerpc/sysv.S
@@ -83,6 +83,7 @@ ENTRY(ffi_call_SYSV)
nop
1:
+#ifndef __NO_FPRS__
/* Load all the FP registers. */
bf- 6,2f
lfd %f1,-16-(8*4)-(8*8)(%r28)
@@ -94,6 +95,7 @@ ENTRY(ffi_call_SYSV)
lfd %f6,-16-(8*4)-(3*8)(%r28)
lfd %f7,-16-(8*4)-(2*8)(%r28)
lfd %f8,-16-(8*4)-(1*8)(%r28)
+#endif
2:
/* Make the call. */
@@ -103,7 +105,9 @@ ENTRY(ffi_call_SYSV)
mtcrf 0x01,%r31 /* cr7 */
bt- 31,L(small_struct_return_value)
bt- 30,L(done_return_value)
+#ifndef __NO_FPRS__
bt- 29,L(fp_return_value)
+#endif
stw %r3,0(%r30)
bf+ 28,L(done_return_value)
stw %r4,4(%r30)
@@ -124,6 +128,7 @@ L(done_return_value):
lwz %r1,0(%r1)
blr
+#ifndef __NO_FPRS__
L(fp_return_value):
bf 28,L(float_return_value)
stfd %f1,0(%r30)
@@ -134,6 +139,7 @@ L(fp_return_value):
L(float_return_value):
stfs %f1,0(%r30)
b L(done_return_value)
+#endif
L(small_struct_return_value):
/*

View File

@@ -35,3 +35,4 @@ minix
interix-patch interix-patch
remove-debug-code remove-debug-code
powerpc-ffi-softfloat

View File

@@ -41,27 +41,28 @@ enum {
/* The assembly depends on these exact flags. */ /* The assembly depends on these exact flags. */
FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */ FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */
#ifndef __NO_FPRS__
FLAG_RETURNS_FP = 1 << (31-29), FLAG_RETURNS_FP = 1 << (31-29),
#endif
FLAG_RETURNS_64BITS = 1 << (31-28), FLAG_RETURNS_64BITS = 1 << (31-28),
FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */ FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */
FLAG_ARG_NEEDS_COPY = 1 << (31- 7), FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
#ifndef __NO_FPRS__
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
#endif
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
FLAG_RETVAL_REFERENCE = 1 << (31- 4) FLAG_RETVAL_REFERENCE = 1 << (31- 4)
}; };
/* About the SYSV ABI. */ /* About the SYSV ABI. */
unsigned int NUM_GPR_ARG_REGISTERS = 8; #define ASM_NEEDS_REGISTERS 4
#define NUM_GPR_ARG_REGISTERS 8
#ifndef __NO_FPRS__ #ifndef __NO_FPRS__
unsigned int NUM_FPR_ARG_REGISTERS = 8; # define NUM_FPR_ARG_REGISTERS 8
#else
unsigned int NUM_FPR_ARG_REGISTERS = 0;
#endif #endif
enum { ASM_NEEDS_REGISTERS = 4 };
/* ffi_prep_args_SYSV is called by the assembly routine once stack space /* ffi_prep_args_SYSV is called by the assembly routine once stack space
has been allocated for the function's arguments. has been allocated for the function's arguments.
@@ -110,10 +111,12 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
valp gpr_base; valp gpr_base;
int intarg_count; int intarg_count;
#ifndef __NO_FPRS__
/* 'fpr_base' points at the space for fpr1, and grows upwards as /* 'fpr_base' points at the space for fpr1, and grows upwards as
we use FPR registers. */ we use FPR registers. */
valp fpr_base; valp fpr_base;
int fparg_count; int fparg_count;
#endif
/* 'copy_space' grows down as we put structures in it. It should /* 'copy_space' grows down as we put structures in it. It should
stay 16-byte aligned. */ stay 16-byte aligned. */
@@ -122,9 +125,8 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
/* 'next_arg' grows up as we put parameters in it. */ /* 'next_arg' grows up as we put parameters in it. */
valp next_arg; valp next_arg;
int i, ii MAYBE_UNUSED; int i;
ffi_type **ptr; ffi_type **ptr;
double double_tmp;
union { union {
void **v; void **v;
char **c; char **c;
@@ -140,15 +142,16 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
size_t struct_copy_size; size_t struct_copy_size;
unsigned gprvalue; unsigned gprvalue;
if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
NUM_FPR_ARG_REGISTERS = 0;
stacktop.c = (char *) stack + bytes; stacktop.c = (char *) stack + bytes;
gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS; gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
intarg_count = 0; intarg_count = 0;
#ifndef __NO_FPRS__
fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS; fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS;
fparg_count = 0; fparg_count = 0;
copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c);
#else
copy_space.c = gpr_base.c;
#endif
next_arg.u = stack + 2; next_arg.u = stack + 2;
/* Check that everything starts aligned properly. */ /* Check that everything starts aligned properly. */
@@ -171,12 +174,28 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
i > 0; i > 0;
i--, ptr++, p_argv.v++) i--, ptr++, p_argv.v++)
{ {
switch ((*ptr)->type) unsigned short typenum = (*ptr)->type;
{
/* We may need to handle some values depending on ABI */
if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT) {
if (typenum == FFI_TYPE_FLOAT)
typenum = FFI_TYPE_UINT32;
if (typenum == FFI_TYPE_DOUBLE)
typenum = FFI_TYPE_UINT64;
if (typenum == FFI_TYPE_LONGDOUBLE)
typenum = FFI_TYPE_UINT128;
} else if (ecif->cif->abi != FFI_LINUX) {
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (typenum == FFI_TYPE_LONGDOUBLE)
typenum = FFI_TYPE_STRUCT;
#endif
}
/* Now test the translated value */
switch (typenum) {
#ifndef __NO_FPRS__
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
/* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */ /* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_float_prep;
double_tmp = **p_argv.f; double_tmp = **p_argv.f;
if (fparg_count >= NUM_FPR_ARG_REGISTERS) if (fparg_count >= NUM_FPR_ARG_REGISTERS)
{ {
@@ -215,43 +234,6 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
if ((ecif->cif->abi != FFI_LINUX)
&& (ecif->cif->abi != FFI_LINUX_SOFT_FLOAT))
goto do_struct;
/* The soft float ABI for long doubles works like this,
a long double is passed in four consecutive gprs if available.
A maximum of 2 long doubles can be passed in gprs.
If we do not have 4 gprs left, the long double is passed on the
stack, 4-byte aligned. */
if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
{
unsigned int int_tmp = (*p_argv.ui)[0];
if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
{
if (intarg_count < NUM_GPR_ARG_REGISTERS)
intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
*next_arg.u = int_tmp;
next_arg.u++;
for (ii = 1; ii < 4; ii++)
{
int_tmp = (*p_argv.ui)[ii];
*next_arg.u = int_tmp;
next_arg.u++;
}
}
else
{
*gpr_base.u++ = int_tmp;
for (ii = 1; ii < 4; ii++)
{
int_tmp = (*p_argv.ui)[ii];
*gpr_base.u++ = int_tmp;
}
}
intarg_count +=4;
}
else
{
double_tmp = (*p_argv.d)[0]; double_tmp = (*p_argv.d)[0];
if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1) if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
@@ -277,13 +259,40 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
fparg_count += 2; fparg_count += 2;
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
}
break; break;
#endif #endif
#endif /* have FPRs */
/*
* The soft float ABI for long doubles works like this, a long double
* is passed in four consecutive GPRs if available. A maximum of 2
* long doubles can be passed in gprs. If we do not have 4 GPRs
* left, the long double is passed on the stack, 4-byte aligned.
*/
case FFI_TYPE_UINT128: {
unsigned int int_tmp = (*p_argv.ui)[0];
unsigned int ii;
if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3) {
if (intarg_count < NUM_GPR_ARG_REGISTERS)
intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
*(next_arg.u++) = int_tmp;
for (ii = 1; ii < 4; ii++) {
int_tmp = (*p_argv.ui)[ii];
*(next_arg.u++) = int_tmp;
}
} else {
*(gpr_base.u++) = int_tmp;
for (ii = 1; ii < 4; ii++) {
int_tmp = (*p_argv.ui)[ii];
*(gpr_base.u++) = int_tmp;
}
}
intarg_count += 4;
break;
}
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
soft_double_prep:
if (intarg_count == NUM_GPR_ARG_REGISTERS-1) if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
intarg_count++; intarg_count++;
if (intarg_count >= NUM_GPR_ARG_REGISTERS) if (intarg_count >= NUM_GPR_ARG_REGISTERS)
@@ -316,9 +325,6 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
break; break;
case FFI_TYPE_STRUCT: case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
do_struct:
#endif
struct_copy_size = ((*ptr)->size + 15) & ~0xF; struct_copy_size = ((*ptr)->size + 15) & ~0xF;
copy_space.c -= struct_copy_size; copy_space.c -= struct_copy_size;
memcpy (copy_space.c, *p_argv.c, (*ptr)->size); memcpy (copy_space.c, *p_argv.c, (*ptr)->size);
@@ -346,7 +352,6 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
case FFI_TYPE_UINT32: case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32: case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER: case FFI_TYPE_POINTER:
soft_float_prep:
gprvalue = **p_argv.ui; gprvalue = **p_argv.ui;
@@ -363,8 +368,10 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
/* Check that we didn't overrun the stack... */ /* Check that we didn't overrun the stack... */
FFI_ASSERT (copy_space.c >= next_arg.c); FFI_ASSERT (copy_space.c >= next_arg.c);
FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS); FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS);
#ifndef __NO_FPRS__
FFI_ASSERT (fpr_base.u FFI_ASSERT (fpr_base.u
<= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS);
#endif
FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4);
} }
@@ -601,9 +608,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
unsigned type = cif->rtype->type; unsigned type = cif->rtype->type;
unsigned size = cif->rtype->size; unsigned size = cif->rtype->size;
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
NUM_FPR_ARG_REGISTERS = 0;
if (cif->abi != FFI_LINUX64) if (cif->abi != FFI_LINUX64)
{ {
/* All the machine-independent calculation of cif->bytes will be wrong. /* All the machine-independent calculation of cif->bytes will be wrong.
@@ -643,25 +647,38 @@ ffi_prep_cif_machdep (ffi_cif *cif)
- Single/double FP values in fpr1, long double in fpr1,fpr2. - Single/double FP values in fpr1, long double in fpr1,fpr2.
- soft-float float/doubles are treated as UINT32/UINT64 respectivley. - soft-float float/doubles are treated as UINT32/UINT64 respectivley.
- soft-float long doubles are returned in gpr3-gpr6. */ - soft-float long doubles are returned in gpr3-gpr6. */
/* First translate for softfloat/nonlinux */
if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
if (type == FFI_TYPE_FLOAT)
type = FFI_TYPE_UINT32;
if (type == FFI_TYPE_DOUBLE)
type = FFI_TYPE_UINT64;
if (type == FFI_TYPE_LONGDOUBLE)
type = FFI_TYPE_UINT128;
} else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (type == FFI_TYPE_LONGDOUBLE)
type = FFI_TYPE_STRUCT;
#endif
}
switch (type) switch (type)
{ {
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #ifndef __NO_FPRS__
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64
&& cif->abi != FFI_LINUX_SOFT_FLOAT)
goto byref;
flags |= FLAG_RETURNS_128BITS; flags |= FLAG_RETURNS_128BITS;
/* Fall through. */ /* Fall through. */
#endif
case FFI_TYPE_DOUBLE: case FFI_TYPE_DOUBLE:
flags |= FLAG_RETURNS_64BITS; flags |= FLAG_RETURNS_64BITS;
/* Fall through. */ /* Fall through. */
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
/* With FFI_LINUX_SOFT_FLOAT no fp registers are used. */
if (cif->abi != FFI_LINUX_SOFT_FLOAT)
flags |= FLAG_RETURNS_FP; flags |= FLAG_RETURNS_FP;
break; break;
#endif
case FFI_TYPE_UINT128:
flags |= FLAG_RETURNS_128BITS;
/* Fall through. */
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
flags |= FLAG_RETURNS_64BITS; flags |= FLAG_RETURNS_64BITS;
@@ -680,10 +697,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
*/ */
if (cif->abi == FFI_SYSV && size <= 8) if (cif->abi == FFI_SYSV && size <= 8)
flags |= FLAG_RETURNS_SMST; flags |= FLAG_RETURNS_SMST;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
byref:
#endif
intarg_count++; intarg_count++;
flags |= FLAG_RETVAL_REFERENCE; flags |= FLAG_RETVAL_REFERENCE;
/* Fall through. */ /* Fall through. */
@@ -704,39 +717,36 @@ ffi_prep_cif_machdep (ffi_cif *cif)
Stuff on the stack needs to keep proper alignment. */ Stuff on the stack needs to keep proper alignment. */
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{ {
switch ((*ptr)->type) unsigned short typenum = (*ptr)->type;
{
/* We may need to handle some values depending on ABI */
if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
if (typenum == FFI_TYPE_FLOAT)
typenum = FFI_TYPE_UINT32;
if (typenum == FFI_TYPE_DOUBLE)
typenum = FFI_TYPE_UINT64;
if (typenum == FFI_TYPE_LONGDOUBLE)
typenum = FFI_TYPE_UINT128;
} else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (typenum == FFI_TYPE_LONGDOUBLE)
typenum = FFI_TYPE_STRUCT;
#endif
}
switch (typenum) {
#ifndef __NO_FPRS__
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
/* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_float_cif;
fparg_count++; fparg_count++;
/* floating singles are not 8-aligned on stack */ /* floating singles are not 8-aligned on stack */
break; break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
goto do_struct;
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
{
if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
|| intarg_count < NUM_GPR_ARG_REGISTERS)
/* A long double in FFI_LINUX_SOFT_FLOAT can use only
a set of four consecutive gprs. If we have not enough,
we have to adjust the intarg_count value. */
intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
intarg_count += 4;
break;
}
else
fparg_count++; fparg_count++;
/* Fall thru */ /* Fall thru */
#endif #endif
case FFI_TYPE_DOUBLE: case FFI_TYPE_DOUBLE:
/* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_double_cif;
fparg_count++; fparg_count++;
/* If this FP arg is going on the stack, it must be /* If this FP arg is going on the stack, it must be
8-byte-aligned. */ 8-byte-aligned. */
@@ -745,10 +755,21 @@ ffi_prep_cif_machdep (ffi_cif *cif)
&& intarg_count % 2 != 0) && intarg_count % 2 != 0)
intarg_count++; intarg_count++;
break; break;
#endif
case FFI_TYPE_UINT128:
/*
* A long double in FFI_LINUX_SOFT_FLOAT can use only a set
* of four consecutive gprs. If we do not have enough, we
* have to adjust the intarg_count value.
*/
if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
&& intarg_count < NUM_GPR_ARG_REGISTERS)
intarg_count = NUM_GPR_ARG_REGISTERS;
intarg_count += 4;
break;
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
soft_double_cif:
/* 'long long' arguments are passed as two words, but /* 'long long' arguments are passed as two words, but
either both words must fit in registers or both go either both words must fit in registers or both go
on the stack. If they go on the stack, they must on the stack. If they go on the stack, they must
@@ -765,9 +786,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
break; break;
case FFI_TYPE_STRUCT: case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
do_struct:
#endif
/* We must allocate space for a copy of these to enforce /* We must allocate space for a copy of these to enforce
pass-by-value. Pad the space up to a multiple of 16 pass-by-value. Pad the space up to a multiple of 16
bytes (the maximum alignment required for anything under bytes (the maximum alignment required for anything under
@@ -775,12 +793,20 @@ ffi_prep_cif_machdep (ffi_cif *cif)
struct_copy_size += ((*ptr)->size + 15) & ~0xF; struct_copy_size += ((*ptr)->size + 15) & ~0xF;
/* Fall through (allocate space for the pointer). */ /* Fall through (allocate space for the pointer). */
default: case FFI_TYPE_POINTER:
soft_float_cif: case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
/* Everything else is passed as a 4-byte word in a GPR, either /* Everything else is passed as a 4-byte word in a GPR, either
the object itself or a pointer to it. */ the object itself or a pointer to it. */
intarg_count++; intarg_count++;
break; break;
default:
FFI_ASSERT (0);
} }
} }
else else
@@ -809,16 +835,29 @@ ffi_prep_cif_machdep (ffi_cif *cif)
intarg_count += ((*ptr)->size + 7) / 8; intarg_count += ((*ptr)->size + 7) / 8;
break; break;
default: case FFI_TYPE_POINTER:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_INT:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
/* Everything else is passed as a 8-byte word in a GPR, either /* Everything else is passed as a 8-byte word in a GPR, either
the object itself or a pointer to it. */ the object itself or a pointer to it. */
intarg_count++; intarg_count++;
break; break;
default:
FFI_ASSERT (0);
} }
} }
#ifndef __NO_FPRS__
if (fparg_count != 0) if (fparg_count != 0)
flags |= FLAG_FP_ARGUMENTS; flags |= FLAG_FP_ARGUMENTS;
#endif
if (intarg_count > 4) if (intarg_count > 4)
flags |= FLAG_4_GPR_ARGUMENTS; flags |= FLAG_4_GPR_ARGUMENTS;
if (struct_copy_size != 0) if (struct_copy_size != 0)
@@ -826,21 +865,27 @@ ffi_prep_cif_machdep (ffi_cif *cif)
if (cif->abi != FFI_LINUX64) if (cif->abi != FFI_LINUX64)
{ {
#ifndef __NO_FPRS__
/* Space for the FPR registers, if needed. */ /* Space for the FPR registers, if needed. */
if (fparg_count != 0) if (fparg_count != 0)
bytes += NUM_FPR_ARG_REGISTERS * sizeof (double); bytes += NUM_FPR_ARG_REGISTERS * sizeof (double);
#endif
/* Stack space. */ /* Stack space. */
if (intarg_count > NUM_GPR_ARG_REGISTERS) if (intarg_count > NUM_GPR_ARG_REGISTERS)
bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int); bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int);
#ifndef __NO_FPRS__
if (fparg_count > NUM_FPR_ARG_REGISTERS) if (fparg_count > NUM_FPR_ARG_REGISTERS)
bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double); bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double);
#endif
} }
else else
{ {
#ifndef __NO_FPRS__
/* Space for the FPR registers, if needed. */ /* Space for the FPR registers, if needed. */
if (fparg_count != 0) if (fparg_count != 0)
bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
#endif
/* Stack space. */ /* Stack space. */
if (intarg_count > NUM_GPR_ARG_REGISTERS64) if (intarg_count > NUM_GPR_ARG_REGISTERS64)
@@ -898,9 +943,11 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
switch (cif->abi) switch (cif->abi)
{ {
#ifndef POWERPC64 #ifndef POWERPC64
# ifndef __NO_FPRS__
case FFI_SYSV: case FFI_SYSV:
case FFI_GCC_SYSV: case FFI_GCC_SYSV:
case FFI_LINUX: case FFI_LINUX:
# endif
case FFI_LINUX_SOFT_FLOAT: case FFI_LINUX_SOFT_FLOAT:
ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
break; break;
@@ -1013,32 +1060,38 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
void ** avalue; void ** avalue;
ffi_type ** arg_types; ffi_type ** arg_types;
long i, avn; long i, avn;
long nf; /* number of floating registers already used */ #ifndef __NO_FPRS__
long ng; /* number of general registers already used */ long nf = 0; /* number of floating registers already used */
ffi_cif * cif; #endif
double temp; long ng = 0; /* number of general registers already used */
unsigned size;
ffi_cif *cif = closure->cif;
unsigned size = cif->rtype->size;
unsigned short rtypenum = cif->rtype->type;
cif = closure->cif;
avalue = alloca (cif->nargs * sizeof (void *)); avalue = alloca (cif->nargs * sizeof (void *));
size = cif->rtype->size;
nf = 0; /* First translate for softfloat/nonlinux */
ng = 0; if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
if (rtypenum == FFI_TYPE_FLOAT)
rtypenum = FFI_TYPE_UINT32;
if (rtypenum == FFI_TYPE_DOUBLE)
rtypenum = FFI_TYPE_UINT64;
if (rtypenum == FFI_TYPE_LONGDOUBLE)
rtypenum = FFI_TYPE_UINT128;
} else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (rtypenum == FFI_TYPE_LONGDOUBLE)
rtypenum = FFI_TYPE_STRUCT;
#endif
}
/* Copy the caller's structure return value address so that the closure /* Copy the caller's structure return value address so that the closure
returns the data directly to the caller. returns the data directly to the caller.
For FFI_SYSV the result is passed in r3/r4 if the struct size is less For FFI_SYSV the result is passed in r3/r4 if the struct size is less
or equal 8 bytes. */ or equal 8 bytes. */
if (rtypenum == FFI_TYPE_STRUCT && ((cif->abi != FFI_SYSV) || (size > 8))) {
if ((cif->rtype->type == FFI_TYPE_STRUCT
&& !((cif->abi == FFI_SYSV) && (size <= 8)))
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| (cif->rtype->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
#endif
)
{
rvalue = (void *) *pgr; rvalue = (void *) *pgr;
ng++; ng++;
pgr++; pgr++;
@@ -1049,10 +1102,109 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
arg_types = cif->arg_types; arg_types = cif->arg_types;
/* Grab the addresses of the arguments from the stack frame. */ /* Grab the addresses of the arguments from the stack frame. */
while (i < avn) while (i < avn) {
unsigned short typenum = arg_types[i]->type;
/* We may need to handle some values depending on ABI */
if (cif->abi == FFI_LINUX_SOFT_FLOAT) {
if (typenum == FFI_TYPE_FLOAT)
typenum = FFI_TYPE_UINT32;
if (typenum == FFI_TYPE_DOUBLE)
typenum = FFI_TYPE_UINT64;
if (typenum == FFI_TYPE_LONGDOUBLE)
typenum = FFI_TYPE_UINT128;
} else if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) {
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (typenum == FFI_TYPE_LONGDOUBLE)
typenum = FFI_TYPE_STRUCT;
#endif
}
switch (typenum) {
#ifndef __NO_FPRS__
case FFI_TYPE_FLOAT:
/* unfortunately float values are stored as doubles
* in the ffi_closure_SYSV code (since we don't check
* the type in that routine).
*/
/* there are 8 64bit floating point registers */
if (nf < 8)
{ {
switch (arg_types[i]->type) temp = pfr->d;
pfr->f = (float) temp;
avalue[i] = pfr;
nf++;
pfr++;
}
else
{ {
/* FIXME? here we are really changing the values
* stored in the original calling routines outgoing
* parameter stack. This is probably a really
* naughty thing to do but...
*/
avalue[i] = pst;
pst += 1;
}
break;
case FFI_TYPE_DOUBLE:
/* On the outgoing stack all values are aligned to 8 */
/* there are 8 64bit floating point registers */
if (nf < 8)
{
avalue[i] = pfr;
nf++;
pfr++;
}
else
{
if (((long) pst) & 4)
pst++;
avalue[i] = pst;
pst += 2;
}
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
if (nf < 7)
{
avalue[i] = pfr;
pfr += 2;
nf += 2;
}
else
{
if (((long) pst) & 4)
pst++;
avalue[i] = pst;
pst += 4;
nf = 8;
}
break;
#endif
#endif /* have FPRS */
case FFI_TYPE_UINT128:
/*
* Test if for the whole long double, 4 gprs are available.
* otherwise the stuff ends up on the stack.
*/
if (ng < 5) {
avalue[i] = pgr;
pgr += 4;
ng += 4;
} else {
avalue[i] = pst;
pst += 4;
ng = 8+4;
}
break;
case FFI_TYPE_SINT8: case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8: case FFI_TYPE_UINT8:
/* there are 8 gpr registers used to pass values */ /* there are 8 gpr registers used to pass values */
@@ -1088,7 +1240,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
case FFI_TYPE_SINT32: case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32: case FFI_TYPE_UINT32:
case FFI_TYPE_POINTER: case FFI_TYPE_POINTER:
soft_float_closure:
/* there are 8 gpr registers used to pass values */ /* there are 8 gpr registers used to pass values */
if (ng < 8) if (ng < 8)
{ {
@@ -1104,9 +1255,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
break; break;
case FFI_TYPE_STRUCT: case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
do_struct:
#endif
/* Structs are passed by reference. The address will appear in a /* Structs are passed by reference. The address will appear in a
gpr if it is one of the first 8 arguments. */ gpr if it is one of the first 8 arguments. */
if (ng < 8) if (ng < 8)
@@ -1124,7 +1272,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
soft_double_closure:
/* passing long long ints are complex, they must /* passing long long ints are complex, they must
* be passed in suitable register pairs such as * be passed in suitable register pairs such as
* (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
@@ -1156,97 +1303,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
} }
break; break;
case FFI_TYPE_FLOAT:
/* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_float_closure;
/* unfortunately float values are stored as doubles
* in the ffi_closure_SYSV code (since we don't check
* the type in that routine).
*/
/* there are 8 64bit floating point registers */
if (nf < 8)
{
temp = pfr->d;
pfr->f = (float) temp;
avalue[i] = pfr;
nf++;
pfr++;
}
else
{
/* FIXME? here we are really changing the values
* stored in the original calling routines outgoing
* parameter stack. This is probably a really
* naughty thing to do but...
*/
avalue[i] = pst;
pst += 1;
}
break;
case FFI_TYPE_DOUBLE:
/* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_double_closure;
/* On the outgoing stack all values are aligned to 8 */
/* there are 8 64bit floating point registers */
if (nf < 8)
{
avalue[i] = pfr;
nf++;
pfr++;
}
else
{
if (((long) pst) & 4)
pst++;
avalue[i] = pst;
pst += 2;
}
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
goto do_struct;
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
{ /* Test if for the whole long double, 4 gprs are available.
otherwise the stuff ends up on the stack. */
if (ng < 5)
{
avalue[i] = pgr;
pgr += 4;
ng += 4;
}
else
{
avalue[i] = pst;
pst += 4;
ng = 8;
}
break;
}
if (nf < 7)
{
avalue[i] = pfr;
pfr += 2;
nf += 2;
}
else
{
if (((long) pst) & 4)
pst++;
avalue[i] = pst;
pst += 4;
nf = 8;
}
break;
#endif
default: default:
FFI_ASSERT (0); FFI_ASSERT (0);
} }
@@ -1265,39 +1321,9 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
already used and we never have a struct with size zero. That is the reason already used and we never have a struct with size zero. That is the reason
for the subtraction of 1. See the comment in ffitarget.h about ordering. for the subtraction of 1. See the comment in ffitarget.h about ordering.
*/ */
if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT if (cif->abi == FFI_SYSV && rtypenum == FFI_TYPE_STRUCT && size <= 8)
&& size <= 8)
return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size; return (FFI_SYSV_TYPE_SMALL_STRUCT - 1) + size;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE return rtypenum;
else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
return FFI_TYPE_STRUCT;
#endif
/* With FFI_LINUX_SOFT_FLOAT floats and doubles are handled like UINT32
respectivley UINT64. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
{
switch (cif->rtype->type)
{
case FFI_TYPE_FLOAT:
return FFI_TYPE_UINT32;
break;
case FFI_TYPE_DOUBLE:
return FFI_TYPE_UINT64;
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
return FFI_TYPE_UINT128;
break;
#endif
default:
return cif->rtype->type;
}
}
else
{
return cif->rtype->type;
}
} }
int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *, int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,

1444
src/powerpc/ffi.c.orig Normal file

File diff suppressed because it is too large Load Diff

12
src/powerpc/ffi.c.rej Normal file
View File

@@ -0,0 +1,12 @@
--- src/powerpc/ffi.c
+++ src/powerpc/ffi.c
@@ -717,9 +734,6 @@
}
}
}
-#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
- byref:
-#endif
intarg_count++;
flags |= FLAG_RETVAL_REFERENCE;
/* Fall through. */

View File

@@ -60,20 +60,16 @@ typedef enum ffi_abi {
FFI_LINUX64, FFI_LINUX64,
FFI_LINUX, FFI_LINUX,
FFI_LINUX_SOFT_FLOAT, FFI_LINUX_SOFT_FLOAT,
# ifdef POWERPC64 # if defined(POWERPC64)
FFI_DEFAULT_ABI = FFI_LINUX64, FFI_DEFAULT_ABI = FFI_LINUX64,
# else # elif defined(__NO_FPRS__)
# if (!defined(__NO_FPRS__) && (__LDBL_MANT_DIG__ == 106)) FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT,
# elif (__LDBL_MANT_DIG__ == 106)
FFI_DEFAULT_ABI = FFI_LINUX, FFI_DEFAULT_ABI = FFI_LINUX,
# else
# ifdef __NO_FPRS__
FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT,
# else # else
FFI_DEFAULT_ABI = FFI_GCC_SYSV, FFI_DEFAULT_ABI = FFI_GCC_SYSV,
# endif # endif
#endif #endif
# endif
#endif
#ifdef POWERPC_AIX #ifdef POWERPC_AIX
FFI_AIX, FFI_AIX,

View File

@@ -122,22 +122,41 @@ ENTRY(ffi_closure_SYSV)
blr blr
# case FFI_TYPE_FLOAT # case FFI_TYPE_FLOAT
#ifndef __NO_FPRS__
lfs %f1,112+0(%r1) lfs %f1,112+0(%r1)
mtlr %r0 mtlr %r0
addi %r1,%r1,144 addi %r1,%r1,144
#else
nop
nop
nop
#endif
blr blr
# case FFI_TYPE_DOUBLE # case FFI_TYPE_DOUBLE
#ifndef __NO_FPRS__
lfd %f1,112+0(%r1) lfd %f1,112+0(%r1)
mtlr %r0 mtlr %r0
addi %r1,%r1,144 addi %r1,%r1,144
#else
nop
nop
nop
#endif
blr blr
# case FFI_TYPE_LONGDOUBLE # case FFI_TYPE_LONGDOUBLE
#ifndef __NO_FPRS__
lfd %f1,112+0(%r1) lfd %f1,112+0(%r1)
lfd %f2,112+8(%r1) lfd %f2,112+8(%r1)
mtlr %r0 mtlr %r0
b .Lfinish b .Lfinish
#else
nop
nop
nop
blr
#endif
# case FFI_TYPE_UINT8 # case FFI_TYPE_UINT8
lbz %r3,112+3(%r1) lbz %r3,112+3(%r1)

View File

@@ -83,6 +83,7 @@ ENTRY(ffi_call_SYSV)
nop nop
1: 1:
#ifndef __NO_FPRS__
/* Load all the FP registers. */ /* Load all the FP registers. */
bf- 6,2f bf- 6,2f
lfd %f1,-16-(8*4)-(8*8)(%r28) lfd %f1,-16-(8*4)-(8*8)(%r28)
@@ -94,6 +95,7 @@ ENTRY(ffi_call_SYSV)
lfd %f6,-16-(8*4)-(3*8)(%r28) lfd %f6,-16-(8*4)-(3*8)(%r28)
lfd %f7,-16-(8*4)-(2*8)(%r28) lfd %f7,-16-(8*4)-(2*8)(%r28)
lfd %f8,-16-(8*4)-(1*8)(%r28) lfd %f8,-16-(8*4)-(1*8)(%r28)
#endif
2: 2:
/* Make the call. */ /* Make the call. */
@@ -103,7 +105,9 @@ ENTRY(ffi_call_SYSV)
mtcrf 0x01,%r31 /* cr7 */ mtcrf 0x01,%r31 /* cr7 */
bt- 31,L(small_struct_return_value) bt- 31,L(small_struct_return_value)
bt- 30,L(done_return_value) bt- 30,L(done_return_value)
#ifndef __NO_FPRS__
bt- 29,L(fp_return_value) bt- 29,L(fp_return_value)
#endif
stw %r3,0(%r30) stw %r3,0(%r30)
bf+ 28,L(done_return_value) bf+ 28,L(done_return_value)
stw %r4,4(%r30) stw %r4,4(%r30)
@@ -124,6 +128,7 @@ L(done_return_value):
lwz %r1,0(%r1) lwz %r1,0(%r1)
blr blr
#ifndef __NO_FPRS__
L(fp_return_value): L(fp_return_value):
bf 28,L(float_return_value) bf 28,L(float_return_value)
stfd %f1,0(%r30) stfd %f1,0(%r30)
@@ -134,6 +139,7 @@ L(fp_return_value):
L(float_return_value): L(float_return_value):
stfs %f1,0(%r30) stfs %f1,0(%r30)
b L(done_return_value) b L(done_return_value)
#endif
L(small_struct_return_value): L(small_struct_return_value):
/* /*

214
src/powerpc/sysv.S.orig Normal file
View File

@@ -0,0 +1,214 @@
/* -----------------------------------------------------------------------
sysv.S - Copyright (c) 1998 Geoffrey Keating
Copyright (C) 2007 Free Software Foundation, Inc
PowerPC Assembly glue.
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 THE AUTHORS OR COPYRIGHT
HOLDERS 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 <fficonfig.h>
#include <ffi.h>
#include <powerpc/asm.h>
#ifndef __powerpc64__
.globl ffi_prep_args_SYSV
ENTRY(ffi_call_SYSV)
.LFB1:
/* Save the old stack pointer as AP. */
mr %r8,%r1
.LCFI0:
/* Allocate the stack space we need. */
stwux %r1,%r1,%r4
/* Save registers we use. */
mflr %r9
stw %r28,-16(%r8)
.LCFI1:
stw %r29,-12(%r8)
.LCFI2:
stw %r30, -8(%r8)
.LCFI3:
stw %r31, -4(%r8)
.LCFI4:
stw %r9, 4(%r8)
.LCFI5:
/* Save arguments over call... */
mr %r31,%r5 /* flags, */
mr %r30,%r6 /* rvalue, */
mr %r29,%r7 /* function address, */
mr %r28,%r8 /* our AP. */
.LCFI6:
/* Call ffi_prep_args_SYSV. */
mr %r4,%r1
bl ffi_prep_args_SYSV@local
/* Now do the call. */
/* Set up cr1 with bits 4-7 of the flags. */
mtcrf 0x40,%r31
/* Get the address to call into CTR. */
mtctr %r29
/* Load all those argument registers. */
lwz %r3,-16-(8*4)(%r28)
lwz %r4,-16-(7*4)(%r28)
lwz %r5,-16-(6*4)(%r28)
lwz %r6,-16-(5*4)(%r28)
bf- 5,1f
nop
lwz %r7,-16-(4*4)(%r28)
lwz %r8,-16-(3*4)(%r28)
lwz %r9,-16-(2*4)(%r28)
lwz %r10,-16-(1*4)(%r28)
nop
1:
/* Load all the FP registers. */
bf- 6,2f
lfd %f1,-16-(8*4)-(8*8)(%r28)
lfd %f2,-16-(8*4)-(7*8)(%r28)
lfd %f3,-16-(8*4)-(6*8)(%r28)
lfd %f4,-16-(8*4)-(5*8)(%r28)
nop
lfd %f5,-16-(8*4)-(4*8)(%r28)
lfd %f6,-16-(8*4)-(3*8)(%r28)
lfd %f7,-16-(8*4)-(2*8)(%r28)
lfd %f8,-16-(8*4)-(1*8)(%r28)
2:
/* Make the call. */
bctrl
/* Now, deal with the return value. */
mtcrf 0x01,%r31 /* cr7 */
bt- 31,L(small_struct_return_value)
bt- 30,L(done_return_value)
bt- 29,L(fp_return_value)
stw %r3,0(%r30)
bf+ 28,L(done_return_value)
stw %r4,4(%r30)
mtcrf 0x02,%r31 /* cr6 */
bf 27,L(done_return_value)
stw %r5,8(%r30)
stw %r6,12(%r30)
/* Fall through... */
L(done_return_value):
/* Restore the registers we used and return. */
lwz %r9, 4(%r28)
lwz %r31, -4(%r28)
mtlr %r9
lwz %r30, -8(%r28)
lwz %r29,-12(%r28)
lwz %r28,-16(%r28)
lwz %r1,0(%r1)
blr
L(fp_return_value):
bf 28,L(float_return_value)
stfd %f1,0(%r30)
mtcrf 0x02,%r31 /* cr6 */
bf 27,L(done_return_value)
stfd %f2,8(%r30)
b L(done_return_value)
L(float_return_value):
stfs %f1,0(%r30)
b L(done_return_value)
L(small_struct_return_value):
/*
* The C code always allocates a properly-aligned 8-byte bounce
* buffer to make this assembly code very simple. Just write out
* r3 and r4 to the buffer to allow the C code to handle the rest.
*/
stw %r3, 0(%r30)
stw %r4, 4(%r30)
b L(done_return_value)
.LFE1:
END(ffi_call_SYSV)
.section ".eh_frame",EH_FRAME_FLAGS,@progbits
.Lframe1:
.4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
.LSCIE1:
.4byte 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
#if defined _RELOCATABLE || defined __PIC__
.ascii "zR\0" /* CIE Augmentation */
#else
.ascii "\0" /* CIE Augmentation */
#endif
.uleb128 0x1 /* CIE Code Alignment Factor */
.sleb128 -4 /* CIE Data Alignment Factor */
.byte 0x41 /* CIE RA Column */
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x1 /* Augmentation size */
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
#endif
.byte 0xc /* DW_CFA_def_cfa */
.uleb128 0x1
.uleb128 0x0
.align 2
.LECIE1:
.LSFDE1:
.4byte .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1:
.4byte .LASFDE1-.Lframe1 /* FDE CIE offset */
#if defined _RELOCATABLE || defined __PIC__
.4byte .LFB1-. /* FDE initial location */
#else
.4byte .LFB1 /* FDE initial location */
#endif
.4byte .LFE1-.LFB1 /* FDE address range */
#if defined _RELOCATABLE || defined __PIC__
.uleb128 0x0 /* Augmentation size */
#endif
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI0-.LFB1
.byte 0xd /* DW_CFA_def_cfa_register */
.uleb128 0x08
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI5-.LCFI0
.byte 0x11 /* DW_CFA_offset_extended_sf */
.uleb128 0x41
.sleb128 -1
.byte 0x9f /* DW_CFA_offset, column 0x1f */
.uleb128 0x1
.byte 0x9e /* DW_CFA_offset, column 0x1e */
.uleb128 0x2
.byte 0x9d /* DW_CFA_offset, column 0x1d */
.uleb128 0x3
.byte 0x9c /* DW_CFA_offset, column 0x1c */
.uleb128 0x4
.byte 0x4 /* DW_CFA_advance_loc4 */
.4byte .LCFI6-.LCFI5
.byte 0xd /* DW_CFA_def_cfa_register */
.uleb128 0x1c
.align 2
.LEFDE1:
#endif
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif