Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
46e0720d
Commit
46e0720d
authored
14 years ago
by
Chung-Lin Tang
Committed by
Anthony Green
14 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add ARM VFP ABI support to libffi.
From-SVN: r166032
parent
f17aa4ad
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
484 additions
and
30 deletions
+484
-30
libffi/ChangeLog
+38
-0
libffi/src/arm/ffi.c
+211
-20
libffi/src/arm/ffitarget.h
+17
-1
libffi/src/arm/sysv.S
+164
-9
libffi/testsuite/lib/libffi-dg.exp
+50
-0
libffi/testsuite/libffi.call/cls_double_va.c
+2
-0
libffi/testsuite/libffi.call/cls_longdouble_va.c
+2
-0
No files found.
libffi/ChangeLog
View file @
46e0720d
2010-10-28 Chung-Lin Tang <cltang@codesourcery.com>
* src/arm/ffi.c (ffi_prep_args): Add VFP register argument handling
code, new parameter, and return value. Update comments.
(ffi_prep_cif_machdep): Add case for VFP struct return values. Add
call to layout_vfp_args().
(ffi_call_SYSV): Update declaration.
(ffi_call_VFP): New declaration.
(ffi_call): Add VFP struct return conditions. Call ffi_call_VFP()
when ABI is FFI_VFP.
(ffi_closure_VFP): New declaration.
(ffi_closure_SYSV_inner): Add new vfp_args parameter, update call to
ffi_prep_incoming_args_SYSV().
(ffi_prep_incoming_args_SYSV): Update parameters. Add VFP argument
case handling.
(ffi_prep_closure_loc): Pass ffi_closure_VFP to trampoline
construction under VFP hard-float.
(rec_vfp_type_p): New function.
(vfp_type_p): Same.
(place_vfp_arg): Same.
(layout_vfp_args): Same.
* src/arm/ffitarget.h (ffi_abi): Add FFI_VFP. Define FFI_DEFAULT_ABI
based on __ARM_PCS_VFP.
(FFI_EXTRA_CIF_FIELDS): Define for adding VFP hard-float specific
fields.
(FFI_TYPE_STRUCT_VFP_FLOAT): Define internally used type code.
(FFI_TYPE_STRUCT_VFP_DOUBLE): Same.
* src/arm/sysv.S (ffi_call_SYSV): Change call of ffi_prep_args() to
direct call. Move function pointer load upwards.
(ffi_call_VFP): New function.
(ffi_closure_VFP): Same.
* testsuite/lib/libffi-dg.exp (check-flags): New function.
(dg-skip-if): New function.
* testsuite/libffi.call/cls_double_va.c: Skip if target is arm*-*-*
and compiler options include -mfloat-abi=hard.
* testsuite/libffi.call/cls_longdouble_va.c: Same.
2010-10-01 Jakub Jelinek <jakub@redhat.com>
PR libffi/45677
...
...
This diff is collapsed.
Click to expand it.
libffi/src/arm/ffi.c
View file @
46e0720d
...
...
@@ -29,12 +29,20 @@
#include <stdlib.h>
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
/* Forward declares. */
static
int
vfp_type_p
(
ffi_type
*
);
static
void
layout_vfp_args
(
ffi_cif
*
);
void
ffi_prep_args
(
char
*
stack
,
extended_cif
*
ecif
)
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments
The vfp_space parameter is the load area for VFP regs, the return
value is cif->vfp_used (word bitset of VFP regs used for passing
arguments). These are only used for the VFP hard-float ABI.
*/
int
ffi_prep_args
(
char
*
stack
,
extended_cif
*
ecif
,
float
*
vfp_space
)
{
register
unsigned
int
i
;
register
unsigned
int
i
,
vi
=
0
;
register
void
**
p_argv
;
register
char
*
argp
;
register
ffi_type
**
p_arg
;
...
...
@@ -54,6 +62,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
{
size_t
z
;
/* Allocated in VFP registers. */
if
(
ecif
->
cif
->
abi
==
FFI_VFP
&&
vi
<
ecif
->
cif
->
vfp_nargs
&&
vfp_type_p
(
*
p_arg
))
{
float
*
vfp_slot
=
vfp_space
+
ecif
->
cif
->
vfp_args
[
vi
++
];
if
((
*
p_arg
)
->
type
==
FFI_TYPE_FLOAT
)
*
((
float
*
)
vfp_slot
)
=
*
((
float
*
)
*
p_argv
);
else
if
((
*
p_arg
)
->
type
==
FFI_TYPE_DOUBLE
)
*
((
double
*
)
vfp_slot
)
=
*
((
double
*
)
*
p_argv
);
else
memcpy
(
vfp_slot
,
*
p_argv
,
(
*
p_arg
)
->
size
);
p_argv
++
;
continue
;
}
/* Align if necessary */
if
(((
*
p_arg
)
->
alignment
-
1
)
&
(
unsigned
)
argp
)
{
argp
=
(
char
*
)
ALIGN
(
argp
,
(
*
p_arg
)
->
alignment
);
...
...
@@ -103,13 +126,15 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
p_argv
++
;
argp
+=
z
;
}
return
;
/* Indicate the VFP registers used. */
return
ecif
->
cif
->
vfp_used
;
}
/* Perform machine dependent cif processing */
ffi_status
ffi_prep_cif_machdep
(
ffi_cif
*
cif
)
{
int
type_code
;
/* Round the stack up to a multiple of 8 bytes. This isn't needed
everywhere, but it is on some platforms, and it doesn't harm anything
when it isn't needed. */
...
...
@@ -130,7 +155,14 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
break
;
case
FFI_TYPE_STRUCT
:
if
(
cif
->
rtype
->
size
<=
4
)
if
(
cif
->
abi
==
FFI_VFP
&&
(
type_code
=
vfp_type_p
(
cif
->
rtype
))
!=
0
)
{
/* A Composite Type passed in VFP registers, either
FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
cif
->
flags
=
(
unsigned
)
type_code
;
}
else
if
(
cif
->
rtype
->
size
<=
4
)
/* A Composite Type not larger than 4 bytes is returned in r0. */
cif
->
flags
=
(
unsigned
)
FFI_TYPE_INT
;
else
...
...
@@ -145,11 +177,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
break
;
}
/* Map out the register placements of VFP register args.
The VFP hard-float calling conventions are slightly more sophisticated than
the base calling conventions, so we do it here instead of in ffi_prep_args(). */
if
(
cif
->
abi
==
FFI_VFP
)
layout_vfp_args
(
cif
);
return
FFI_OK
;
}
extern
void
ffi_call_SYSV
(
void
(
*
)(
char
*
,
extended_cif
*
),
extended_cif
*
,
unsigned
,
unsigned
,
unsigned
*
,
void
(
*
fn
)(
void
));
/* Prototypes for assembly functions, in sysv.S */
extern
void
ffi_call_SYSV
(
void
(
*
fn
)(
void
),
extended_cif
*
,
unsigned
,
unsigned
,
unsigned
*
);
extern
void
ffi_call_VFP
(
void
(
*
fn
)(
void
),
extended_cif
*
,
unsigned
,
unsigned
,
unsigned
*
);
void
ffi_call
(
ffi_cif
*
cif
,
void
(
*
fn
)(
void
),
void
*
rvalue
,
void
**
avalue
)
{
...
...
@@ -157,6 +196,8 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
int
small_struct
=
(
cif
->
flags
==
FFI_TYPE_INT
&&
cif
->
rtype
->
type
==
FFI_TYPE_STRUCT
);
int
vfp_struct
=
(
cif
->
flags
==
FFI_TYPE_STRUCT_VFP_FLOAT
||
cif
->
flags
==
FFI_TYPE_STRUCT_VFP_DOUBLE
);
ecif
.
cif
=
cif
;
ecif
.
avalue
=
avalue
;
...
...
@@ -173,38 +214,51 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
else
if
(
small_struct
)
ecif
.
rvalue
=
&
temp
;
else
if
(
vfp_struct
)
{
/* Largest case is double x 4. */
ecif
.
rvalue
=
alloca
(
32
);
}
else
ecif
.
rvalue
=
rvalue
;
switch
(
cif
->
abi
)
{
case
FFI_SYSV
:
ffi_call_SYSV
(
ffi_prep_args
,
&
ecif
,
cif
->
bytes
,
cif
->
flags
,
ecif
.
rvalue
,
fn
)
;
ffi_call_SYSV
(
fn
,
&
ecif
,
cif
->
bytes
,
cif
->
flags
,
ecif
.
rvalue
);
break
;
case
FFI_VFP
:
ffi_call_VFP
(
fn
,
&
ecif
,
cif
->
bytes
,
cif
->
flags
,
ecif
.
rvalue
);
break
;
default:
FFI_ASSERT
(
0
);
break
;
}
if
(
small_struct
)
memcpy
(
rvalue
,
&
temp
,
cif
->
rtype
->
size
);
else
if
(
vfp_struct
)
memcpy
(
rvalue
,
ecif
.
rvalue
,
cif
->
rtype
->
size
);
}
/** private members **/
static
void
ffi_prep_incoming_args_SYSV
(
char
*
stack
,
void
**
ret
,
void
**
args
,
ffi_cif
*
cif
);
void
**
args
,
ffi_cif
*
cif
,
float
*
vfp_stack
);
void
ffi_closure_SYSV
(
ffi_closure
*
);
void
ffi_closure_VFP
(
ffi_closure
*
);
/* This function is jumped to by the trampoline */
unsigned
int
ffi_closure_SYSV_inner
(
closure
,
respp
,
args
)
ffi_closure_SYSV_inner
(
closure
,
respp
,
args
,
vfp_args
)
ffi_closure
*
closure
;
void
**
respp
;
void
*
args
;
void
*
vfp_args
;
{
// our various things...
ffi_cif
*
cif
;
...
...
@@ -219,7 +273,7 @@ ffi_closure_SYSV_inner (closure, respp, args)
* a structure, it will re-set RESP to point to the
* structure return address. */
ffi_prep_incoming_args_SYSV
(
args
,
respp
,
arg_area
,
cif
);
ffi_prep_incoming_args_SYSV
(
args
,
respp
,
arg_area
,
cif
,
vfp_args
);
(
closure
->
fun
)
(
cif
,
*
respp
,
arg_area
,
closure
->
user_data
);
...
...
@@ -229,10 +283,12 @@ ffi_closure_SYSV_inner (closure, respp, args)
/*@-exportheader@*/
static
void
ffi_prep_incoming_args_SYSV
(
char
*
stack
,
void
**
rvalue
,
void
**
avalue
,
ffi_cif
*
cif
)
void
**
avalue
,
ffi_cif
*
cif
,
/* Used only under VFP hard-float ABI. */
float
*
vfp_stack
)
/*@=exportheader@*/
{
register
unsigned
int
i
;
register
unsigned
int
i
,
vi
=
0
;
register
void
**
p_argv
;
register
char
*
argp
;
register
ffi_type
**
p_arg
;
...
...
@@ -249,8 +305,16 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
for
(
i
=
cif
->
nargs
,
p_arg
=
cif
->
arg_types
;
(
i
!=
0
);
i
--
,
p_arg
++
)
{
size_t
z
;
size_t
alignment
=
(
*
p_arg
)
->
alignment
;
size_t
alignment
;
if
(
cif
->
abi
==
FFI_VFP
&&
vi
<
cif
->
vfp_nargs
&&
vfp_type_p
(
*
p_arg
))
{
*
p_argv
++
=
(
void
*
)(
vfp_stack
+
cif
->
vfp_args
[
vi
++
]);
continue
;
}
alignment
=
(
*
p_arg
)
->
alignment
;
if
(
alignment
<
4
)
alignment
=
4
;
/* Align if necessary */
...
...
@@ -295,10 +359,17 @@ ffi_prep_closure_loc (ffi_closure* closure,
void
*
user_data
,
void
*
codeloc
)
{
FFI_ASSERT
(
cif
->
abi
==
FFI_SYSV
)
;
void
(
*
closure_func
)(
ffi_closure
*
)
=
NULL
;
if
(
cif
->
abi
==
FFI_SYSV
)
closure_func
=
&
ffi_closure_SYSV
;
else
if
(
cif
->
abi
==
FFI_VFP
)
closure_func
=
&
ffi_closure_VFP
;
else
FFI_ASSERT
(
0
);
FFI_INIT_TRAMPOLINE
(
&
closure
->
tramp
[
0
],
\
&
ffi_closure_SYSV
,
\
closure_func
,
\
codeloc
);
closure
->
cif
=
cif
;
...
...
@@ -307,3 +378,123 @@ ffi_prep_closure_loc (ffi_closure* closure,
return
FFI_OK
;
}
/* Below are routines for VFP hard-float support. */
static
int
rec_vfp_type_p
(
ffi_type
*
t
,
int
*
elt
,
int
*
elnum
)
{
switch
(
t
->
type
)
{
case
FFI_TYPE_FLOAT
:
case
FFI_TYPE_DOUBLE
:
*
elt
=
(
int
)
t
->
type
;
*
elnum
=
1
;
return
1
;
case
FFI_TYPE_STRUCT_VFP_FLOAT
:
*
elt
=
FFI_TYPE_FLOAT
;
*
elnum
=
t
->
size
/
sizeof
(
float
);
return
1
;
case
FFI_TYPE_STRUCT_VFP_DOUBLE
:
*
elt
=
FFI_TYPE_DOUBLE
;
*
elnum
=
t
->
size
/
sizeof
(
double
);
return
1
;
case
FFI_TYPE_STRUCT
:;
{
int
base_elt
=
0
,
total_elnum
=
0
;
ffi_type
**
el
=
t
->
elements
;
while
(
*
el
)
{
int
el_elt
=
0
,
el_elnum
=
0
;
if
(
!
rec_vfp_type_p
(
*
el
,
&
el_elt
,
&
el_elnum
)
||
(
base_elt
&&
base_elt
!=
el_elt
)
||
total_elnum
+
el_elnum
>
4
)
return
0
;
base_elt
=
el_elt
;
total_elnum
+=
el_elnum
;
el
++
;
}
*
elnum
=
total_elnum
;
*
elt
=
base_elt
;
return
1
;
}
default
:
;
}
return
0
;
}
static
int
vfp_type_p
(
ffi_type
*
t
)
{
int
elt
,
elnum
;
if
(
rec_vfp_type_p
(
t
,
&
elt
,
&
elnum
))
{
if
(
t
->
type
==
FFI_TYPE_STRUCT
)
{
if
(
elnum
==
1
)
t
->
type
=
elt
;
else
t
->
type
=
(
elt
==
FFI_TYPE_FLOAT
?
FFI_TYPE_STRUCT_VFP_FLOAT
:
FFI_TYPE_STRUCT_VFP_DOUBLE
);
}
return
(
int
)
t
->
type
;
}
return
0
;
}
static
void
place_vfp_arg
(
ffi_cif
*
cif
,
ffi_type
*
t
)
{
int
reg
=
cif
->
vfp_reg_free
;
int
nregs
=
t
->
size
/
sizeof
(
float
);
int
align
=
((
t
->
type
==
FFI_TYPE_STRUCT_VFP_FLOAT
||
t
->
type
==
FFI_TYPE_FLOAT
)
?
1
:
2
);
/* Align register number. */
if
((
reg
&
1
)
&&
align
==
2
)
reg
++
;
while
(
reg
+
nregs
<=
16
)
{
int
s
,
new_used
=
0
;
for
(
s
=
reg
;
s
<
reg
+
nregs
;
s
++
)
{
new_used
|=
(
1
<<
s
);
if
(
cif
->
vfp_used
&
(
1
<<
s
))
{
reg
+=
align
;
goto
next_reg
;
}
}
/* Found regs to allocate. */
cif
->
vfp_used
|=
new_used
;
cif
->
vfp_args
[
cif
->
vfp_nargs
++
]
=
reg
;
/* Update vfp_reg_free. */
if
(
cif
->
vfp_used
&
(
1
<<
cif
->
vfp_reg_free
))
{
reg
+=
nregs
;
while
(
cif
->
vfp_used
&
(
1
<<
reg
))
reg
+=
1
;
cif
->
vfp_reg_free
=
reg
;
}
return
;
next_reg
:
;
}
}
static
void
layout_vfp_args
(
ffi_cif
*
cif
)
{
int
i
;
/* Init VFP fields */
cif
->
vfp_used
=
0
;
cif
->
vfp_nargs
=
0
;
cif
->
vfp_reg_free
=
0
;
memset
(
cif
->
vfp_args
,
-
1
,
16
);
/* Init to -1. */
for
(
i
=
0
;
i
<
cif
->
nargs
;
i
++
)
{
ffi_type
*
t
=
cif
->
arg_types
[
i
];
if
(
vfp_type_p
(
t
))
place_vfp_arg
(
cif
,
t
);
}
}
This diff is collapsed.
Click to expand it.
libffi/src/arm/ffitarget.h
View file @
46e0720d
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Copyright (c) 2010 CodeSourcery
Target configuration macros for ARM.
Permission is hereby granted, free of charge, to any person obtaining
...
...
@@ -34,11 +36,25 @@ typedef signed long ffi_sarg;
typedef
enum
ffi_abi
{
FFI_FIRST_ABI
=
0
,
FFI_SYSV
,
FFI_VFP
,
FFI_LAST_ABI
,
#ifdef __ARM_PCS_VFP
FFI_DEFAULT_ABI
=
FFI_VFP
,
#else
FFI_DEFAULT_ABI
=
FFI_SYSV
,
FFI_LAST_ABI
=
FFI_DEFAULT_ABI
+
1
#endif
}
ffi_abi
;
#endif
#define FFI_EXTRA_CIF_FIELDS \
int vfp_used; \
short vfp_reg_free, vfp_nargs; \
signed char vfp_args[16] \
/* Internally used. */
#define FFI_TYPE_STRUCT_VFP_FLOAT (FFI_TYPE_LAST + 1)
#define FFI_TYPE_STRUCT_VFP_DOUBLE (FFI_TYPE_LAST + 2)
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
...
...
This diff is collapsed.
Click to expand it.
libffi/src/arm/sysv.S
View file @
46e0720d
...
...
@@ -142,12 +142,11 @@ _L__\name:
.endm
@ r0: f
fi_prep_args
@ r0: f
n
@ r1: &ecif
@ r2: cif->bytes
@ r3: fig->flags
@ sp+0: ecif.rvalue
@ sp+4: fn
@ This assumes we are using gas.
ARM_FUNC_START ffi_call_SYSV
...
...
@@ -162,24 +161,23 @@ ARM_FUNC_START ffi_call_SYSV
sub sp, fp, r2
@ Place all of the ffi_prep_args in position
mov ip, r0
mov r0, sp
@ r1 already set
@ Call ffi_prep_args(stack, &ecif)
call_reg(ip)
bl ffi_prep_args
@ move first 4 parameters in registers
ldmia sp, {r0-r3}
@ and adjust stack
ldr ip, [fp, #8]
cmp ip, #16
movhs ip, #16
add sp, sp, ip
sub lr, fp, sp @ cif->bytes == fp - sp
ldr ip, [fp] @ load fn() in advance
cmp lr, #16
movhs lr, #16
add sp, sp, lr
@ call (fn) (...)
ldr ip, [fp, #28]
call_reg(ip)
@ Remove the space we pushed for the args
...
...
@@ -230,6 +228,101 @@ LSYM(Lepilogue):
UNWIND .fnend
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
@ r0: fn
@ r1: &ecif
@ r2: cif->bytes
@ r3: fig->flags
@ sp+0: ecif.rvalue
ARM_FUNC_START ffi_call_VFP
@ Save registers
stmfd sp!, {r0-r3, fp, lr}
UNWIND .save {r0-r3, fp, lr}
mov fp, sp
UNWIND .setfp fp, sp
@ Make room for all of the new args.
sub sp, sp, r2
@ Make room for loading VFP args
sub sp, sp, #64
@ Place all of the ffi_prep_args in position
mov r0, sp
@ r1 already set
sub r2, fp, #64 @ VFP scratch space
@ Call ffi_prep_args(stack, &ecif, vfp_space)
bl ffi_prep_args
@ Load VFP register args if needed
cmp r0, #0
beq LSYM(Lbase_args)
@ Load only d0 if possible
cmp r0, #3
sub ip, fp, #64
flddle d0, [ip]
fldmiadgt ip, {d0-d7}
LSYM(Lbase_args):
@ move first 4 parameters in registers
ldmia sp, {r0-r3}
@ and adjust stack
sub lr, ip, sp @ cif->bytes == (fp - 64) - sp
ldr ip, [fp] @ load fn() in advance
cmp lr, #16
movhs lr, #16
add sp, sp, lr
@ call (fn) (...)
call_reg(ip)
@ Remove the space we pushed for the args
mov sp, fp
@ Load r2 with the pointer to storage for
@ the return value
ldr r2, [sp, #24]
@ Load r3 with the return type code
ldr r3, [sp, #12]
@ If the return value pointer is NULL,
@ assume no return value.
cmp r2, #0
beq LSYM(Lepilogue_vfp)
cmp r3, #FFI_TYPE_INT
streq r0, [r2]
beq LSYM(Lepilogue_vfp)
cmp r3, #FFI_TYPE_SINT64
stmeqia r2, {r0, r1}
beq LSYM(Lepilogue_vfp)
cmp r3, #FFI_TYPE_FLOAT
fstseq s0, [r2]
beq LSYM(Lepilogue_vfp)
cmp r3, #FFI_TYPE_DOUBLE
fstdeq d0, [r2]
beq LSYM(Lepilogue_vfp)
cmp r3, #FFI_TYPE_STRUCT_VFP_FLOAT
cmpne r3, #FFI_TYPE_STRUCT_VFP_DOUBLE
fstmiadeq r2, {d0-d3}
LSYM(Lepilogue_vfp):
RETLDM "r0-r3,fp"
.ffi_call_VFP_end:
UNWIND .fnend
.size CNAME(ffi_call_VFP),.ffi_call_VFP_end-CNAME(ffi_call_VFP)
/*
unsigned int FFI_HIDDEN
ffi_closure_SYSV_inner (closure, respp, args)
...
...
@@ -302,6 +395,68 @@ ARM_FUNC_START ffi_closure_SYSV
UNWIND .fnend
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
ARM_FUNC_START ffi_closure_VFP
fstmfdd sp!, {d0-d7}
@ r0-r3, then d0-d7
UNWIND .pad #80
add ip, sp, #80
stmfd sp!, {ip, lr}
UNWIND .save {r0, lr}
add r2, sp, #72
add r3, sp, #8
.pad #72
sub sp, sp, #72
str sp, [sp, #64]
add r1, sp, #64
bl ffi_closure_SYSV_inner
cmp r0, #FFI_TYPE_INT
beq .Lretint_vfp
cmp r0, #FFI_TYPE_FLOAT
beq .Lretfloat_vfp
cmp r0, #FFI_TYPE_DOUBLE
cmpne r0, #FFI_TYPE_LONGDOUBLE
beq .Lretdouble_vfp
cmp r0, #FFI_TYPE_SINT64
beq .Lretlonglong_vfp
cmp r0, #FFI_TYPE_STRUCT_VFP_FLOAT
beq .Lretfloat_struct_vfp
cmp r0, #FFI_TYPE_STRUCT_VFP_DOUBLE
beq .Lretdouble_struct_vfp
.Lclosure_epilogue_vfp:
add sp, sp, #72
ldmfd sp, {sp, pc}
.Lretfloat_vfp:
flds s0, [sp]
b .Lclosure_epilogue_vfp
.Lretdouble_vfp:
fldd d0, [sp]
b .Lclosure_epilogue_vfp
.Lretint_vfp:
ldr r0, [sp]
b .Lclosure_epilogue_vfp
.Lretlonglong_vfp:
ldmia sp, {r0, r1}
b .Lclosure_epilogue_vfp
.Lretfloat_struct_vfp:
fldmiad sp, {d0-d1}
b .Lclosure_epilogue_vfp
.Lretdouble_struct_vfp:
fldmiad sp, {d0-d3}
b .Lclosure_epilogue_vfp
.ffi_closure_VFP_end:
UNWIND .fnend
.size CNAME(ffi_closure_VFP),.ffi_closure_VFP_end-CNAME(ffi_closure_VFP)
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",%progbits
#endif
This diff is collapsed.
Click to expand it.
libffi/testsuite/lib/libffi-dg.exp
View file @
46e0720d
...
...
@@ -272,6 +272,56 @@ proc dg-xfail-if { args } {
}
}
proc check-flags { args } {
# The args are within another list; pull them out.
set args [lindex $args 0]
# The next two arguments are optional. If they were not specified,
# use the defaults.
if { [llength $args] == 2 } {
lappend $args [list "*"]
}
if { [llength $args] == 3 } {
lappend $args [list ""]
}
# If the option strings are the defaults, or the same as the
# defaults, there is no need to call check_conditional_xfail to
# compare them to the actual options.
if { [string compare [lindex $args 2] "*"] == 0
&& [string compare [lindex $args 3] "" ] == 0 } {
set result 1
} else {
# The target list might be an effective-target keyword, so replace
# the original list with "*-*-*", since we already know it matches.
set result [check_conditional_xfail [lreplace $args 1 1 "*-*-*"]]
}
return $result
}
proc dg-skip-if { args } {
# Verify the number of arguments. The last two are optional.
set args [lreplace $args 0 0]
if { [llength $args] < 2 || [llength $args] > 4 } {
error "dg-skip-if 2: need 2, 3, or 4 arguments"
}
# Don't bother if we're already skipping the test.
upvar dg-do-what dg-do-what
if { [lindex ${dg-do-what} 1] == "N" } {
return
}
set selector [list target [lindex $args 1]]
if { [dg-process-target $selector] == "S" } {
if [check-flags $args] {
upvar dg-do-what dg-do-what
set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"]
}
}
}
# We need to make sure that additional_files and additional_sources
# are both cleared out after every test. It is not enough to clear
...
...
This diff is collapsed.
Click to expand it.
libffi/testsuite/libffi.call/cls_double_va.c
View file @
46e0720d
...
...
@@ -6,6 +6,8 @@
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
/* { dg-output "" { xfail avr32*-*-* } } */
/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
#include "ffitest.h"
static
void
...
...
This diff is collapsed.
Click to expand it.
libffi/testsuite/libffi.call/cls_longdouble_va.c
View file @
46e0720d
...
...
@@ -6,6 +6,8 @@
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
#include "ffitest.h"
static
void
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment