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
Oct 28, 2010
by
Chung-Lin Tang
Committed by
Anthony Green
Oct 28, 2010
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>
2010-10-01 Jakub Jelinek <jakub@redhat.com>
PR libffi/45677
PR libffi/45677
...
...
libffi/src/arm/ffi.c
View file @
46e0720d
...
@@ -29,12 +29,20 @@
...
@@ -29,12 +29,20 @@
#include <stdlib.h>
#include <stdlib.h>
/* ffi_prep_args is called by the assembly routine once stack space
/* Forward declares. */
has been allocated for the function's arguments */
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
void
**
p_argv
;
register
char
*
argp
;
register
char
*
argp
;
register
ffi_type
**
p_arg
;
register
ffi_type
**
p_arg
;
...
@@ -54,6 +62,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
...
@@ -54,6 +62,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
{
{
size_t
z
;
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 */
/* Align if necessary */
if
(((
*
p_arg
)
->
alignment
-
1
)
&
(
unsigned
)
argp
)
{
if
(((
*
p_arg
)
->
alignment
-
1
)
&
(
unsigned
)
argp
)
{
argp
=
(
char
*
)
ALIGN
(
argp
,
(
*
p_arg
)
->
alignment
);
argp
=
(
char
*
)
ALIGN
(
argp
,
(
*
p_arg
)
->
alignment
);
...
@@ -103,13 +126,15 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
...
@@ -103,13 +126,15 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
p_argv
++
;
p_argv
++
;
argp
+=
z
;
argp
+=
z
;
}
}
return
;
/* Indicate the VFP registers used. */
return
ecif
->
cif
->
vfp_used
;
}
}
/* Perform machine dependent cif processing */
/* Perform machine dependent cif processing */
ffi_status
ffi_prep_cif_machdep
(
ffi_cif
*
cif
)
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
/* 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
everywhere, but it is on some platforms, and it doesn't harm anything
when it isn't needed. */
when it isn't needed. */
...
@@ -130,7 +155,14 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
...
@@ -130,7 +155,14 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
break
;
break
;
case
FFI_TYPE_STRUCT
:
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. */
/* A Composite Type not larger than 4 bytes is returned in r0. */
cif
->
flags
=
(
unsigned
)
FFI_TYPE_INT
;
cif
->
flags
=
(
unsigned
)
FFI_TYPE_INT
;
else
else
...
@@ -145,11 +177,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
...
@@ -145,11 +177,18 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
break
;
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
;
return
FFI_OK
;
}
}
extern
void
ffi_call_SYSV
(
void
(
*
)(
char
*
,
extended_cif
*
),
extended_cif
*
,
/* Prototypes for assembly functions, in sysv.S */
unsigned
,
unsigned
,
unsigned
*
,
void
(
*
fn
)(
void
));
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
)
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)
...
@@ -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
int
small_struct
=
(
cif
->
flags
==
FFI_TYPE_INT
&&
cif
->
rtype
->
type
==
FFI_TYPE_STRUCT
);
&&
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
.
cif
=
cif
;
ecif
.
avalue
=
avalue
;
ecif
.
avalue
=
avalue
;
...
@@ -173,38 +214,51 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
...
@@ -173,38 +214,51 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
}
else
if
(
small_struct
)
else
if
(
small_struct
)
ecif
.
rvalue
=
&
temp
;
ecif
.
rvalue
=
&
temp
;
else
if
(
vfp_struct
)
{
/* Largest case is double x 4. */
ecif
.
rvalue
=
alloca
(
32
);
}
else
else
ecif
.
rvalue
=
rvalue
;
ecif
.
rvalue
=
rvalue
;
switch
(
cif
->
abi
)
switch
(
cif
->
abi
)
{
{
case
FFI_SYSV
:
case
FFI_SYSV
:
ffi_call_SYSV
(
ffi_prep_args
,
&
ecif
,
cif
->
bytes
,
cif
->
flags
,
ecif
.
rvalue
,
ffi_call_SYSV
(
fn
,
&
ecif
,
cif
->
bytes
,
cif
->
flags
,
ecif
.
rvalue
);
fn
)
;
break
;
case
FFI_VFP
:
ffi_call_VFP
(
fn
,
&
ecif
,
cif
->
bytes
,
cif
->
flags
,
ecif
.
rvalue
);
break
;
break
;
default:
default:
FFI_ASSERT
(
0
);
FFI_ASSERT
(
0
);
break
;
break
;
}
}
if
(
small_struct
)
if
(
small_struct
)
memcpy
(
rvalue
,
&
temp
,
cif
->
rtype
->
size
);
memcpy
(
rvalue
,
&
temp
,
cif
->
rtype
->
size
);
else
if
(
vfp_struct
)
memcpy
(
rvalue
,
ecif
.
rvalue
,
cif
->
rtype
->
size
);
}
}
/** private members **/
/** private members **/
static
void
ffi_prep_incoming_args_SYSV
(
char
*
stack
,
void
**
ret
,
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_SYSV
(
ffi_closure
*
);
void
ffi_closure_VFP
(
ffi_closure
*
);
/* This function is jumped to by the trampoline */
/* This function is jumped to by the trampoline */
unsigned
int
unsigned
int
ffi_closure_SYSV_inner
(
closure
,
respp
,
args
)
ffi_closure_SYSV_inner
(
closure
,
respp
,
args
,
vfp_args
)
ffi_closure
*
closure
;
ffi_closure
*
closure
;
void
**
respp
;
void
**
respp
;
void
*
args
;
void
*
args
;
void
*
vfp_args
;
{
{
// our various things...
// our various things...
ffi_cif
*
cif
;
ffi_cif
*
cif
;
...
@@ -219,7 +273,7 @@ ffi_closure_SYSV_inner (closure, respp, args)
...
@@ -219,7 +273,7 @@ ffi_closure_SYSV_inner (closure, respp, args)
* a structure, it will re-set RESP to point to the
* a structure, it will re-set RESP to point to the
* structure return address. */
* 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
);
(
closure
->
fun
)
(
cif
,
*
respp
,
arg_area
,
closure
->
user_data
);
...
@@ -229,10 +283,12 @@ ffi_closure_SYSV_inner (closure, respp, args)
...
@@ -229,10 +283,12 @@ ffi_closure_SYSV_inner (closure, respp, args)
/*@-exportheader@*/
/*@-exportheader@*/
static
void
static
void
ffi_prep_incoming_args_SYSV
(
char
*
stack
,
void
**
rvalue
,
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@*/
/*@=exportheader@*/
{
{
register
unsigned
int
i
;
register
unsigned
int
i
,
vi
=
0
;
register
void
**
p_argv
;
register
void
**
p_argv
;
register
char
*
argp
;
register
char
*
argp
;
register
ffi_type
**
p_arg
;
register
ffi_type
**
p_arg
;
...
@@ -249,8 +305,16 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
...
@@ -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
++
)
for
(
i
=
cif
->
nargs
,
p_arg
=
cif
->
arg_types
;
(
i
!=
0
);
i
--
,
p_arg
++
)
{
{
size_t
z
;
size_t
z
;
size_t
alignment
;
size_t
alignment
=
(
*
p_arg
)
->
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
)
if
(
alignment
<
4
)
alignment
=
4
;
alignment
=
4
;
/* Align if necessary */
/* Align if necessary */
...
@@ -295,10 +359,17 @@ ffi_prep_closure_loc (ffi_closure* closure,
...
@@ -295,10 +359,17 @@ ffi_prep_closure_loc (ffi_closure* closure,
void
*
user_data
,
void
*
user_data
,
void
*
codeloc
)
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_INIT_TRAMPOLINE
(
&
closure
->
tramp
[
0
],
\
&
ffi_closure_SYSV
,
\
closure_func
,
\
codeloc
);
codeloc
);
closure
->
cif
=
cif
;
closure
->
cif
=
cif
;
...
@@ -307,3 +378,123 @@ ffi_prep_closure_loc (ffi_closure* closure,
...
@@ -307,3 +378,123 @@ ffi_prep_closure_loc (ffi_closure* closure,
return
FFI_OK
;
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
);
}
}
libffi/src/arm/ffitarget.h
View file @
46e0720d
/* -----------------------------------------------------------------*-C-*-
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Copyright (c) 2010 CodeSourcery
Target configuration macros for ARM.
Target configuration macros for ARM.
Permission is hereby granted, free of charge, to any person obtaining
Permission is hereby granted, free of charge, to any person obtaining
...
@@ -34,11 +36,25 @@ typedef signed long ffi_sarg;
...
@@ -34,11 +36,25 @@ typedef signed long ffi_sarg;
typedef
enum
ffi_abi
{
typedef
enum
ffi_abi
{
FFI_FIRST_ABI
=
0
,
FFI_FIRST_ABI
=
0
,
FFI_SYSV
,
FFI_SYSV
,
FFI_VFP
,
FFI_LAST_ABI
,
#ifdef __ARM_PCS_VFP
FFI_DEFAULT_ABI
=
FFI_VFP
,
#else
FFI_DEFAULT_ABI
=
FFI_SYSV
,
FFI_DEFAULT_ABI
=
FFI_SYSV
,
FFI_LAST_ABI
=
FFI_DEFAULT_ABI
+
1
#endif
}
ffi_abi
;
}
ffi_abi
;
#endif
#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 ----------------------------------------- */
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_CLOSURES 1
...
...
libffi/src/arm/sysv.S
View file @
46e0720d
...
@@ -142,12 +142,11 @@ _L__\name:
...
@@ -142,12 +142,11 @@ _L__\name:
.endm
.endm
@ r0: f
fi_prep_args
@ r0: f
n
@ r1: &ecif
@ r1: &ecif
@ r2: cif->bytes
@ r2: cif->bytes
@ r3: fig->flags
@ r3: fig->flags
@ sp+0: ecif.rvalue
@ sp+0: ecif.rvalue
@ sp+4: fn
@ This assumes we are using gas.
@ This assumes we are using gas.
ARM_FUNC_START ffi_call_SYSV
ARM_FUNC_START ffi_call_SYSV
...
@@ -162,24 +161,23 @@ ARM_FUNC_START ffi_call_SYSV
...
@@ -162,24 +161,23 @@ ARM_FUNC_START ffi_call_SYSV
sub sp, fp, r2
sub sp, fp, r2
@ Place all of the ffi_prep_args in position
@ Place all of the ffi_prep_args in position
mov ip, r0
mov r0, sp
mov r0, sp
@ r1 already set
@ r1 already set
@ Call ffi_prep_args(stack, &ecif)
@ Call ffi_prep_args(stack, &ecif)
call_reg(ip)
bl ffi_prep_args
@ move first 4 parameters in registers
@ move first 4 parameters in registers
ldmia sp, {r0-r3}
ldmia sp, {r0-r3}
@ and adjust stack
@ and adjust stack
ldr ip, [fp, #8]
sub lr, fp, sp @ cif->bytes == fp - sp
cmp ip, #16
ldr ip, [fp] @ load fn() in advance
movhs ip, #16
cmp lr, #16
add sp, sp, ip
movhs lr, #16
add sp, sp, lr
@ call (fn) (...)
@ call (fn) (...)
ldr ip, [fp, #28]
call_reg(ip)
call_reg(ip)
@ Remove the space we pushed for the args
@ Remove the space we pushed for the args
...
@@ -230,6 +228,101 @@ LSYM(Lepilogue):
...
@@ -230,6 +228,101 @@ LSYM(Lepilogue):
UNWIND .fnend
UNWIND .fnend
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
.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
unsigned int FFI_HIDDEN
ffi_closure_SYSV_inner (closure, respp, args)
ffi_closure_SYSV_inner (closure, respp, args)
...
@@ -302,6 +395,68 @@ ARM_FUNC_START ffi_closure_SYSV
...
@@ -302,6 +395,68 @@ ARM_FUNC_START ffi_closure_SYSV
UNWIND .fnend
UNWIND .fnend
.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
.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__
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",%progbits
.section .note.GNU-stack,"",%progbits
#endif
#endif
libffi/testsuite/lib/libffi-dg.exp
View file @
46e0720d
...
@@ -272,6 +272,56 @@ proc dg-xfail-if { args } {
...
@@ -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
# We need to make sure that additional_files and additional_sources
# are both cleared out after every test. It is not enough to clear
# are both cleared out after every test. It is not enough to clear
...
...
libffi/testsuite/libffi.call/cls_double_va.c
View file @
46e0720d
...
@@ -6,6 +6,8 @@
...
@@ -6,6 +6,8 @@
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
/* { dg-output "" { xfail avr32*-*-* } } */
/* { dg-output "" { xfail avr32*-*-* } } */
/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
#include "ffitest.h"
#include "ffitest.h"
static
void
static
void
...
...
libffi/testsuite/libffi.call/cls_longdouble_va.c
View file @
46e0720d
...
@@ -6,6 +6,8 @@
...
@@ -6,6 +6,8 @@
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
/* { dg-do run { xfail strongarm*-*-* xscale*-*-* } } */
/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
/* { dg-output "" { xfail avr32*-*-* x86_64-*-mingw* } } */
/* { dg-skip-if "" arm*-*-* { "-mfloat-abi=hard" } { "" } } */
#include "ffitest.h"
#include "ffitest.h"
static
void
static
void
...
...
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