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
de76b467
Commit
de76b467
authored
Mar 22, 2000
by
Jan Hubicka
Committed by
Jan Hubicka
Mar 22, 2000
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
* calls.c: re-install Mar 16 emit_library_call merge.
From-SVN: r32685
parent
7e9d4b22
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
114 additions
and
569 deletions
+114
-569
gcc/ChangeLog
+4
-0
gcc/calls.c
+110
-569
No files found.
gcc/ChangeLog
View file @
de76b467
Wed
Mar
22
11
:
44
:
50
MET
2000
Jan
Hubicka
<
jh
@suse
.
cz
>
*
calls
.
c
:
re
-
install
Mar
16
emit_library_call
merge
.
2000
-
03
-
21
Jakub
Jelinek
<
jakub
@redhat
.
com
>
2000
-
03
-
21
Jakub
Jelinek
<
jakub
@redhat
.
com
>
*
config
/
sparc
/
sparc
.
c
(
mem_min_alignment
)
:
If
not
optimizing
,
*
config
/
sparc
/
sparc
.
c
(
mem_min_alignment
)
:
If
not
optimizing
,
...
...
gcc/calls.c
View file @
de76b467
...
@@ -172,6 +172,9 @@ static rtx rtx_for_function_call PARAMS ((tree, tree));
...
@@ -172,6 +172,9 @@ static rtx rtx_for_function_call PARAMS ((tree, tree));
static
void
load_register_parameters
PARAMS
((
struct
arg_data
*
,
static
void
load_register_parameters
PARAMS
((
struct
arg_data
*
,
int
,
rtx
*
));
int
,
rtx
*
));
static
int
libfunc_nothrow
PARAMS
((
rtx
));
static
int
libfunc_nothrow
PARAMS
((
rtx
));
static
rtx
emit_library_call_value_1
PARAMS
((
int
,
rtx
,
rtx
,
int
,
enum
machine_mode
,
int
,
va_list
));
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
static
rtx
save_fixed_argument_area
PARAMS
((
int
,
rtx
,
int
*
,
int
*
));
static
rtx
save_fixed_argument_area
PARAMS
((
int
,
rtx
,
int
*
,
int
*
));
...
@@ -3026,559 +3029,20 @@ libfunc_nothrow (fun)
...
@@ -3026,559 +3029,20 @@ libfunc_nothrow (fun)
return
1
;
return
1
;
}
}
/* Output a library call to function FUN (a SYMBOL_REF rtx)
(emitting the queue unless NO_QUEUE is nonzero),
for a value of mode OUTMODE,
with NARGS different arguments, passed as alternating rtx values
and machine_modes to convert them to.
The rtx values should have been passed through protect_from_queue already.
NO_QUEUE will be true if and only if the library call is a `const' call
which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent
to the variable is_const in expand_call.
NO_QUEUE must be true for const calls, because if it isn't, then
any pending increment will be emitted between REG_LIBCALL/REG_RETVAL notes,
and will be lost if the libcall sequence is optimized away.
NO_QUEUE must be false for non-const calls, because if it isn't, the
call insn will have its CONST_CALL_P bit set, and it will be incorrectly
optimized. For instance, the instruction scheduler may incorrectly
move memory references across the non-const call. */
void
emit_library_call
VPARAMS
((
rtx
orgfun
,
int
no_queue
,
enum
machine_mode
outmode
,
int
nargs
,
...))
{
#ifndef ANSI_PROTOTYPES
rtx
orgfun
;
int
no_queue
;
enum
machine_mode
outmode
;
int
nargs
;
#endif
va_list
p
;
/* Total size in bytes of all the stack-parms scanned so far. */
struct
args_size
args_size
;
/* Size of arguments before any adjustments (such as rounding). */
struct
args_size
original_args_size
;
register
int
argnum
;
rtx
fun
;
int
inc
;
int
count
;
struct
args_size
alignment_pad
;
rtx
argblock
=
0
;
CUMULATIVE_ARGS
args_so_far
;
struct
arg
{
rtx
value
;
enum
machine_mode
mode
;
rtx
reg
;
int
partial
;
struct
args_size
offset
;
struct
args_size
size
;
rtx
save_area
;
};
struct
arg
*
argvec
;
int
old_inhibit_defer_pop
=
inhibit_defer_pop
;
rtx
call_fusage
=
0
;
int
reg_parm_stack_space
=
0
;
int
nothrow
;
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
/* Define the boundary of the register parm stack space that needs to be
save, if any. */
int
low_to_save
=
-
1
,
high_to_save
=
0
;
rtx
save_area
=
0
;
/* Place that it is saved */
#endif
#ifdef ACCUMULATE_OUTGOING_ARGS
int
initial_highest_arg_in_use
=
highest_outgoing_arg_in_use
;
char
*
initial_stack_usage_map
=
stack_usage_map
;
int
needed
;
#endif
#ifdef REG_PARM_STACK_SPACE
/* Size of the stack reserved for parameter registers. */
#ifdef MAYBE_REG_PARM_STACK_SPACE
reg_parm_stack_space
=
MAYBE_REG_PARM_STACK_SPACE
;
#else
reg_parm_stack_space
=
REG_PARM_STACK_SPACE
((
tree
)
0
);
#endif
#endif
VA_START
(
p
,
nargs
);
#ifndef ANSI_PROTOTYPES
orgfun
=
va_arg
(
p
,
rtx
);
no_queue
=
va_arg
(
p
,
int
);
outmode
=
va_arg
(
p
,
enum
machine_mode
);
nargs
=
va_arg
(
p
,
int
);
#endif
fun
=
orgfun
;
nothrow
=
libfunc_nothrow
(
fun
);
/* Copy all the libcall-arguments out of the varargs data
and into a vector ARGVEC.
Compute how to pass each argument. We only support a very small subset
of the full argument passing conventions to limit complexity here since
library functions shouldn't have many args. */
argvec
=
(
struct
arg
*
)
alloca
(
nargs
*
sizeof
(
struct
arg
));
bzero
((
char
*
)
argvec
,
nargs
*
sizeof
(
struct
arg
));
INIT_CUMULATIVE_ARGS
(
args_so_far
,
NULL_TREE
,
fun
,
0
);
args_size
.
constant
=
0
;
args_size
.
var
=
0
;
push_temp_slots
();
#ifdef PREFERRED_STACK_BOUNDARY
/* Ensure current function's preferred stack boundary is at least
what we need. */
if
(
cfun
->
preferred_stack_boundary
<
PREFERRED_STACK_BOUNDARY
)
cfun
->
preferred_stack_boundary
=
PREFERRED_STACK_BOUNDARY
;
#endif
for
(
count
=
0
;
count
<
nargs
;
count
++
)
{
rtx
val
=
va_arg
(
p
,
rtx
);
enum
machine_mode
mode
=
va_arg
(
p
,
enum
machine_mode
);
/* We cannot convert the arg value to the mode the library wants here;
must do it earlier where we know the signedness of the arg. */
if
(
mode
==
BLKmode
||
(
GET_MODE
(
val
)
!=
mode
&&
GET_MODE
(
val
)
!=
VOIDmode
))
abort
();
/* On some machines, there's no way to pass a float to a library fcn.
Pass it as a double instead. */
#ifdef LIBGCC_NEEDS_DOUBLE
if
(
LIBGCC_NEEDS_DOUBLE
&&
mode
==
SFmode
)
val
=
convert_modes
(
DFmode
,
SFmode
,
val
,
0
),
mode
=
DFmode
;
#endif
/* There's no need to call protect_from_queue, because
either emit_move_insn or emit_push_insn will do that. */
/* Make sure it is a reasonable operand for a move or push insn. */
if
(
GET_CODE
(
val
)
!=
REG
&&
GET_CODE
(
val
)
!=
MEM
&&
!
(
CONSTANT_P
(
val
)
&&
LEGITIMATE_CONSTANT_P
(
val
)))
val
=
force_operand
(
val
,
NULL_RTX
);
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
if
(
FUNCTION_ARG_PASS_BY_REFERENCE
(
args_so_far
,
mode
,
NULL_TREE
,
1
))
{
/* We do not support FUNCTION_ARG_CALLEE_COPIES here since it can
be viewed as just an efficiency improvement. */
rtx
slot
=
assign_stack_temp
(
mode
,
GET_MODE_SIZE
(
mode
),
0
);
emit_move_insn
(
slot
,
val
);
val
=
force_operand
(
XEXP
(
slot
,
0
),
NULL_RTX
);
mode
=
Pmode
;
}
#endif
argvec
[
count
].
value
=
val
;
argvec
[
count
].
mode
=
mode
;
argvec
[
count
].
reg
=
FUNCTION_ARG
(
args_so_far
,
mode
,
NULL_TREE
,
1
);
#ifdef FUNCTION_ARG_PARTIAL_NREGS
argvec
[
count
].
partial
=
FUNCTION_ARG_PARTIAL_NREGS
(
args_so_far
,
mode
,
NULL_TREE
,
1
);
#else
argvec
[
count
].
partial
=
0
;
#endif
locate_and_pad_parm
(
mode
,
NULL_TREE
,
argvec
[
count
].
reg
&&
argvec
[
count
].
partial
==
0
,
NULL_TREE
,
&
args_size
,
&
argvec
[
count
].
offset
,
&
argvec
[
count
].
size
,
&
alignment_pad
);
if
(
argvec
[
count
].
size
.
var
)
abort
();
if
(
reg_parm_stack_space
==
0
&&
argvec
[
count
].
partial
)
argvec
[
count
].
size
.
constant
-=
argvec
[
count
].
partial
*
UNITS_PER_WORD
;
if
(
argvec
[
count
].
reg
==
0
||
argvec
[
count
].
partial
!=
0
||
reg_parm_stack_space
>
0
)
args_size
.
constant
+=
argvec
[
count
].
size
.
constant
;
FUNCTION_ARG_ADVANCE
(
args_so_far
,
mode
,
(
tree
)
0
,
1
);
}
va_end
(
p
);
#ifdef FINAL_REG_PARM_STACK_SPACE
reg_parm_stack_space
=
FINAL_REG_PARM_STACK_SPACE
(
args_size
.
constant
,
args_size
.
var
);
#endif
/* If this machine requires an external definition for library
functions, write one out. */
assemble_external_libcall
(
fun
);
original_args_size
=
args_size
;
#ifdef PREFERRED_STACK_BOUNDARY
args_size
.
constant
=
(((
args_size
.
constant
+
(
STACK_BYTES
-
1
))
/
STACK_BYTES
)
*
STACK_BYTES
);
#endif
args_size
.
constant
=
MAX
(
args_size
.
constant
,
reg_parm_stack_space
);
#ifndef OUTGOING_REG_PARM_STACK_SPACE
args_size
.
constant
-=
reg_parm_stack_space
;
#endif
if
(
args_size
.
constant
>
current_function_outgoing_args_size
)
current_function_outgoing_args_size
=
args_size
.
constant
;
#ifdef ACCUMULATE_OUTGOING_ARGS
/* Since the stack pointer will never be pushed, it is possible for
the evaluation of a parm to clobber something we have already
written to the stack. Since most function calls on RISC machines
do not use the stack, this is uncommon, but must work correctly.
Therefore, we save any area of the stack that was already written
and that we are using. Here we set up to do this by making a new
stack usage map from the old one.
Another approach might be to try to reorder the argument
evaluations to avoid this conflicting stack usage. */
needed
=
args_size
.
constant
;
#ifndef OUTGOING_REG_PARM_STACK_SPACE
/* Since we will be writing into the entire argument area, the
map must be allocated for its entire size, not just the part that
is the responsibility of the caller. */
needed
+=
reg_parm_stack_space
;
#endif
#ifdef ARGS_GROW_DOWNWARD
highest_outgoing_arg_in_use
=
MAX
(
initial_highest_arg_in_use
,
needed
+
1
);
#else
highest_outgoing_arg_in_use
=
MAX
(
initial_highest_arg_in_use
,
needed
);
#endif
stack_usage_map
=
(
char
*
)
alloca
(
highest_outgoing_arg_in_use
);
if
(
initial_highest_arg_in_use
)
bcopy
(
initial_stack_usage_map
,
stack_usage_map
,
initial_highest_arg_in_use
);
if
(
initial_highest_arg_in_use
!=
highest_outgoing_arg_in_use
)
bzero
(
&
stack_usage_map
[
initial_highest_arg_in_use
],
highest_outgoing_arg_in_use
-
initial_highest_arg_in_use
);
needed
=
0
;
/* The address of the outgoing argument list must not be copied to a
register here, because argblock would be left pointing to the
wrong place after the call to allocate_dynamic_stack_space below.
*/
argblock
=
virtual_outgoing_args_rtx
;
#else
/* not ACCUMULATE_OUTGOING_ARGS */
#ifndef PUSH_ROUNDING
argblock
=
push_block
(
GEN_INT
(
args_size
.
constant
),
0
,
0
);
#endif
#endif
#ifdef PUSH_ARGS_REVERSED
#ifdef PREFERRED_STACK_BOUNDARY
/* If we push args individually in reverse order, perform stack alignment
before the first push (the last arg). */
if
(
argblock
==
0
)
anti_adjust_stack
(
GEN_INT
(
args_size
.
constant
-
original_args_size
.
constant
));
#endif
#endif
#ifdef PUSH_ARGS_REVERSED
inc
=
-
1
;
argnum
=
nargs
-
1
;
#else
inc
=
1
;
argnum
=
0
;
#endif
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
/* The argument list is the property of the called routine and it
may clobber it. If the fixed area has been used for previous
parameters, we must save and restore it.
Here we compute the boundary of the that needs to be saved, if any. */
#ifdef ARGS_GROW_DOWNWARD
for
(
count
=
0
;
count
<
reg_parm_stack_space
+
1
;
count
++
)
#else
for
(
count
=
0
;
count
<
reg_parm_stack_space
;
count
++
)
#endif
{
if
(
count
>=
highest_outgoing_arg_in_use
||
stack_usage_map
[
count
]
==
0
)
continue
;
if
(
low_to_save
==
-
1
)
low_to_save
=
count
;
high_to_save
=
count
;
}
if
(
low_to_save
>=
0
)
{
int
num_to_save
=
high_to_save
-
low_to_save
+
1
;
enum
machine_mode
save_mode
=
mode_for_size
(
num_to_save
*
BITS_PER_UNIT
,
MODE_INT
,
1
);
rtx
stack_area
;
/* If we don't have the required alignment, must do this in BLKmode. */
if
((
low_to_save
&
(
MIN
(
GET_MODE_SIZE
(
save_mode
),
BIGGEST_ALIGNMENT
/
UNITS_PER_WORD
)
-
1
)))
save_mode
=
BLKmode
;
#ifdef ARGS_GROW_DOWNWARD
stack_area
=
gen_rtx_MEM
(
save_mode
,
memory_address
(
save_mode
,
plus_constant
(
argblock
,
-
high_to_save
)));
#else
stack_area
=
gen_rtx_MEM
(
save_mode
,
memory_address
(
save_mode
,
plus_constant
(
argblock
,
low_to_save
)));
#endif
if
(
save_mode
==
BLKmode
)
{
save_area
=
assign_stack_temp
(
BLKmode
,
num_to_save
,
0
);
emit_block_move
(
validize_mem
(
save_area
),
stack_area
,
GEN_INT
(
num_to_save
),
PARM_BOUNDARY
/
BITS_PER_UNIT
);
}
else
{
save_area
=
gen_reg_rtx
(
save_mode
);
emit_move_insn
(
save_area
,
stack_area
);
}
}
#endif
/* Push the args that need to be pushed. */
/* ARGNUM indexes the ARGVEC array in the order in which the arguments
are to be pushed. */
for
(
count
=
0
;
count
<
nargs
;
count
++
,
argnum
+=
inc
)
{
register
enum
machine_mode
mode
=
argvec
[
argnum
].
mode
;
register
rtx
val
=
argvec
[
argnum
].
value
;
rtx
reg
=
argvec
[
argnum
].
reg
;
int
partial
=
argvec
[
argnum
].
partial
;
#ifdef ACCUMULATE_OUTGOING_ARGS
int
lower_bound
,
upper_bound
,
i
;
#endif
if
(
!
(
reg
!=
0
&&
partial
==
0
))
{
#ifdef ACCUMULATE_OUTGOING_ARGS
/* If this is being stored into a pre-allocated, fixed-size, stack
area, save any previous data at that location. */
#ifdef ARGS_GROW_DOWNWARD
/* stack_slot is negative, but we want to index stack_usage_map
with positive values. */
upper_bound
=
-
argvec
[
argnum
].
offset
.
constant
+
1
;
lower_bound
=
upper_bound
-
argvec
[
argnum
].
size
.
constant
;
#else
lower_bound
=
argvec
[
argnum
].
offset
.
constant
;
upper_bound
=
lower_bound
+
argvec
[
argnum
].
size
.
constant
;
#endif
for
(
i
=
lower_bound
;
i
<
upper_bound
;
i
++
)
if
(
stack_usage_map
[
i
]
/* Don't store things in the fixed argument area at this point;
it has already been saved. */
&&
i
>
reg_parm_stack_space
)
break
;
if
(
i
!=
upper_bound
)
{
/* We need to make a save area. See what mode we can make it. */
enum
machine_mode
save_mode
=
mode_for_size
(
argvec
[
argnum
].
size
.
constant
*
BITS_PER_UNIT
,
MODE_INT
,
1
);
rtx
stack_area
=
gen_rtx_MEM
(
save_mode
,
memory_address
(
save_mode
,
plus_constant
(
argblock
,
argvec
[
argnum
].
offset
.
constant
)));
argvec
[
argnum
].
save_area
=
gen_reg_rtx
(
save_mode
);
emit_move_insn
(
argvec
[
argnum
].
save_area
,
stack_area
);
}
#endif
emit_push_insn
(
val
,
mode
,
NULL_TREE
,
NULL_RTX
,
0
,
partial
,
reg
,
0
,
argblock
,
GEN_INT
(
argvec
[
argnum
].
offset
.
constant
),
reg_parm_stack_space
,
ARGS_SIZE_RTX
(
alignment_pad
));
#ifdef ACCUMULATE_OUTGOING_ARGS
/* Now mark the segment we just used. */
for
(
i
=
lower_bound
;
i
<
upper_bound
;
i
++
)
stack_usage_map
[
i
]
=
1
;
#endif
NO_DEFER_POP
;
}
}
#ifndef PUSH_ARGS_REVERSED
#ifdef PREFERRED_STACK_BOUNDARY
/* If we pushed args in forward order, perform stack alignment
after pushing the last arg. */
if
(
argblock
==
0
)
anti_adjust_stack
(
GEN_INT
(
args_size
.
constant
-
original_args_size
.
constant
));
#endif
#endif
#ifdef PUSH_ARGS_REVERSED
argnum
=
nargs
-
1
;
#else
argnum
=
0
;
#endif
fun
=
prepare_call_address
(
fun
,
NULL_TREE
,
&
call_fusage
,
0
);
/* Now load any reg parms into their regs. */
/* ARGNUM indexes the ARGVEC array in the order in which the arguments
are to be pushed. */
for
(
count
=
0
;
count
<
nargs
;
count
++
,
argnum
+=
inc
)
{
register
rtx
val
=
argvec
[
argnum
].
value
;
rtx
reg
=
argvec
[
argnum
].
reg
;
int
partial
=
argvec
[
argnum
].
partial
;
/* Handle calls that pass values in multiple non-contiguous
locations. The PA64 has examples of this for library calls. */
if
(
reg
!=
0
&&
GET_CODE
(
reg
)
==
PARALLEL
)
emit_group_load
(
reg
,
val
,
GET_MODE_SIZE
(
GET_MODE
(
val
)),
GET_MODE_ALIGNMENT
(
GET_MODE
(
val
)));
else
if
(
reg
!=
0
&&
partial
==
0
)
emit_move_insn
(
reg
,
val
);
NO_DEFER_POP
;
}
/* For version 1.37, try deleting this entirely. */
if
(
!
no_queue
)
emit_queue
();
/* Any regs containing parms remain in use through the call. */
for
(
count
=
0
;
count
<
nargs
;
count
++
)
{
rtx
reg
=
argvec
[
count
].
reg
;
if
(
reg
!=
0
&&
GET_CODE
(
argvec
[
count
].
reg
)
==
PARALLEL
)
use_group_regs
(
&
call_fusage
,
reg
);
else
if
(
reg
!=
0
)
use_reg
(
&
call_fusage
,
reg
);
}
/* Don't allow popping to be deferred, since then
cse'ing of library calls could delete a call and leave the pop. */
NO_DEFER_POP
;
/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
will set inhibit_defer_pop to that value. */
/* The return type is needed to decide how many bytes the function pops.
Signedness plays no role in that, so for simplicity, we pretend it's
always signed. We also assume that the list of arguments passed has
no impact, so we pretend it is unknown. */
emit_call_1
(
fun
,
get_identifier
(
XSTR
(
orgfun
,
0
)),
build_function_type
(
outmode
==
VOIDmode
?
void_type_node
:
type_for_mode
(
outmode
,
0
),
NULL_TREE
),
original_args_size
.
constant
,
args_size
.
constant
,
0
,
FUNCTION_ARG
(
args_so_far
,
VOIDmode
,
void_type_node
,
1
),
outmode
!=
VOIDmode
?
hard_libcall_value
(
outmode
)
:
NULL_RTX
,
old_inhibit_defer_pop
+
1
,
call_fusage
,
((
no_queue
?
ECF_IS_CONST
:
0
)
|
(
nothrow
?
ECF_NOTHROW
:
0
)));
pop_temp_slots
();
/* Now restore inhibit_defer_pop to its actual original value. */
OK_DEFER_POP
;
#ifdef ACCUMULATE_OUTGOING_ARGS
#ifdef REG_PARM_STACK_SPACE
if
(
save_area
)
{
enum
machine_mode
save_mode
=
GET_MODE
(
save_area
);
#ifdef ARGS_GROW_DOWNWARD
rtx
stack_area
=
gen_rtx_MEM
(
save_mode
,
memory_address
(
save_mode
,
plus_constant
(
argblock
,
-
high_to_save
)));
#else
rtx
stack_area
=
gen_rtx_MEM
(
save_mode
,
memory_address
(
save_mode
,
plus_constant
(
argblock
,
low_to_save
)));
#endif
if
(
save_mode
!=
BLKmode
)
emit_move_insn
(
stack_area
,
save_area
);
else
emit_block_move
(
stack_area
,
validize_mem
(
save_area
),
GEN_INT
(
high_to_save
-
low_to_save
+
1
),
PARM_BOUNDARY
/
BITS_PER_UNIT
);
}
#endif
/* If we saved any argument areas, restore them. */
for
(
count
=
0
;
count
<
nargs
;
count
++
)
if
(
argvec
[
count
].
save_area
)
{
enum
machine_mode
save_mode
=
GET_MODE
(
argvec
[
count
].
save_area
);
rtx
stack_area
=
gen_rtx_MEM
(
save_mode
,
memory_address
(
save_mode
,
plus_constant
(
argblock
,
argvec
[
count
].
offset
.
constant
)));
emit_move_insn
(
stack_area
,
argvec
[
count
].
save_area
);
}
highest_outgoing_arg_in_use
=
initial_highest_arg_in_use
;
stack_usage_map
=
initial_stack_usage_map
;
#endif
}
/* Like emit_library_call except that an extra argument, VALUE,
/* Output a library call to function FUN (a SYMBOL_REF rtx).
comes second and says where to store the result.
The RETVAL parameter specifies whether return value needs to be saved, other
(If VALUE is zero, this function chooses a convenient way
parameters are documented in the emit_library_call function bellow. */
to return the value.
static
rtx
emit_library_call_value_1
(
retval
,
orgfun
,
value
,
no_queue
,
outmode
,
nargs
,
p
)
This function returns an rtx for where the value is to be found.
int
retval
;
If VALUE is nonzero, VALUE is returned. */
rtx
orgfun
;
rtx
value
;
rtx
int
no_queue
;
emit_library_call_value
VPARAMS
((
rtx
orgfun
,
rtx
value
,
int
no_queue
,
enum
machine_mode
outmode
;
enum
machine_mode
outmode
,
int
nargs
,
...))
int
nargs
;
va_list
p
;
{
{
#ifndef ANSI_PROTOTYPES
rtx
orgfun
;
rtx
value
;
int
no_queue
;
enum
machine_mode
outmode
;
int
nargs
;
#endif
va_list
p
;
/* Total size in bytes of all the stack-parms scanned so far. */
/* Total size in bytes of all the stack-parms scanned so far. */
struct
args_size
args_size
;
struct
args_size
args_size
;
/* Size of arguments before any adjustments (such as rounding). */
/* Size of arguments before any adjustments (such as rounding). */
...
@@ -3626,16 +3090,6 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
...
@@ -3626,16 +3090,6 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
#endif
#endif
#endif
#endif
VA_START
(
p
,
nargs
);
#ifndef ANSI_PROTOTYPES
orgfun
=
va_arg
(
p
,
rtx
);
value
=
va_arg
(
p
,
rtx
);
no_queue
=
va_arg
(
p
,
int
);
outmode
=
va_arg
(
p
,
enum
machine_mode
);
nargs
=
va_arg
(
p
,
int
);
#endif
is_const
=
no_queue
;
is_const
=
no_queue
;
fun
=
orgfun
;
fun
=
orgfun
;
...
@@ -3650,7 +3104,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
...
@@ -3650,7 +3104,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
/* If this kind of value comes back in memory,
/* If this kind of value comes back in memory,
decide where in memory it should come back. */
decide where in memory it should come back. */
if
(
aggregate_value_p
(
type_for_mode
(
outmode
,
0
)))
if
(
outmode
!=
VOIDmode
&&
aggregate_value_p
(
type_for_mode
(
outmode
,
0
)))
{
{
#ifdef PCC_STATIC_STRUCT_RETURN
#ifdef PCC_STATIC_STRUCT_RETURN
rtx
pointer_reg
rtx
pointer_reg
...
@@ -3763,7 +3217,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
...
@@ -3763,7 +3217,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
be viewed as just an efficiency improvement. */
be viewed as just an efficiency improvement. */
rtx
slot
=
assign_stack_temp
(
mode
,
GET_MODE_SIZE
(
mode
),
0
);
rtx
slot
=
assign_stack_temp
(
mode
,
GET_MODE_SIZE
(
mode
),
0
);
emit_move_insn
(
slot
,
val
);
emit_move_insn
(
slot
,
val
);
val
=
XEXP
(
slot
,
0
);
val
=
force_operand
(
XEXP
(
slot
,
0
),
NULL_RTX
);
mode
=
Pmode
;
mode
=
Pmode
;
}
}
#endif
#endif
...
@@ -3797,7 +3251,6 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
...
@@ -3797,7 +3251,6 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
FUNCTION_ARG_ADVANCE
(
args_so_far
,
mode
,
(
tree
)
0
,
1
);
FUNCTION_ARG_ADVANCE
(
args_so_far
,
mode
,
(
tree
)
0
,
1
);
}
}
va_end
(
p
);
#ifdef FINAL_REG_PARM_STACK_SPACE
#ifdef FINAL_REG_PARM_STACK_SPACE
reg_parm_stack_space
=
FINAL_REG_PARM_STACK_SPACE
(
args_size
.
constant
,
reg_parm_stack_space
=
FINAL_REG_PARM_STACK_SPACE
(
args_size
.
constant
,
...
@@ -4096,16 +3549,19 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
...
@@ -4096,16 +3549,19 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
will set inhibit_defer_pop to that value. */
will set inhibit_defer_pop to that value. */
/* See the comment in emit_library_call about the function type we build
/* The return type is needed to decide how many bytes the function pops.
and pass here. */
Signedness plays no role in that, so for simplicity, we pretend it's
always signed. We also assume that the list of arguments passed has
no impact, so we pretend it is unknown. */
emit_call_1
(
fun
,
emit_call_1
(
fun
,
get_identifier
(
XSTR
(
orgfun
,
0
)),
get_identifier
(
XSTR
(
orgfun
,
0
)),
build_function_type
(
type_for_mode
(
outmode
,
0
),
NULL_TREE
),
build_function_type
(
outmode
==
VOIDmode
?
void_type_node
:
type_for_mode
(
outmode
,
0
),
NULL_TREE
),
original_args_size
.
constant
,
args_size
.
constant
,
original_args_size
.
constant
,
args_size
.
constant
,
struct_value_size
,
struct_value_size
,
FUNCTION_ARG
(
args_so_far
,
VOIDmode
,
void_type_node
,
1
),
FUNCTION_ARG
(
args_so_far
,
VOIDmode
,
void_type_node
,
1
),
mem_value
==
0
?
hard_libcall_value
(
outmode
)
:
NULL_RTX
,
mem_value
==
0
&&
outmode
!=
VOIDmode
?
hard_libcall_value
(
outmode
)
:
NULL_RTX
,
old_inhibit_defer_pop
+
1
,
call_fusage
,
old_inhibit_defer_pop
+
1
,
call_fusage
,
((
is_const
?
ECF_IS_CONST
:
0
)
((
is_const
?
ECF_IS_CONST
:
0
)
|
(
nothrow
?
ECF_NOTHROW
:
0
)));
|
(
nothrow
?
ECF_NOTHROW
:
0
)));
...
@@ -4116,7 +3572,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
...
@@ -4116,7 +3572,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
pop_temp_slots
();
pop_temp_slots
();
/* Copy the value to the right place. */
/* Copy the value to the right place. */
if
(
outmode
!=
VOIDmode
)
if
(
outmode
!=
VOIDmode
&&
retval
)
{
{
if
(
mem_value
)
if
(
mem_value
)
{
{
...
@@ -4177,6 +3633,91 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
...
@@ -4177,6 +3633,91 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
#endif
#endif
return
value
;
return
value
;
}
/* Output a library call to function FUN (a SYMBOL_REF rtx)
(emitting the queue unless NO_QUEUE is nonzero),
for a value of mode OUTMODE,
with NARGS different arguments, passed as alternating rtx values
and machine_modes to convert them to.
The rtx values should have been passed through protect_from_queue already.
NO_QUEUE will be true if and only if the library call is a `const' call
which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent
to the variable is_const in expand_call.
NO_QUEUE must be true for const calls, because if it isn't, then
any pending increment will be emitted between REG_LIBCALL/REG_RETVAL notes,
and will be lost if the libcall sequence is optimized away.
NO_QUEUE must be false for non-const calls, because if it isn't, the
call insn will have its CONST_CALL_P bit set, and it will be incorrectly
optimized. For instance, the instruction scheduler may incorrectly
move memory references across the non-const call. */
void
emit_library_call
VPARAMS
((
rtx
orgfun
,
int
no_queue
,
enum
machine_mode
outmode
,
int
nargs
,
...))
{
#ifndef ANSI_PROTOTYPES
rtx
orgfun
;
int
no_queue
;
enum
machine_mode
outmode
;
int
nargs
;
#endif
va_list
p
;
VA_START
(
p
,
nargs
);
#ifndef ANSI_PROTOTYPES
orgfun
=
va_arg
(
p
,
rtx
);
no_queue
=
va_arg
(
p
,
int
);
outmode
=
va_arg
(
p
,
enum
machine_mode
);
nargs
=
va_arg
(
p
,
int
);
#endif
emit_library_call_value_1
(
0
,
orgfun
,
NULL_RTX
,
no_queue
,
outmode
,
nargs
,
p
);
va_end
(
p
);
}
/* Like emit_library_call except that an extra argument, VALUE,
comes second and says where to store the result.
(If VALUE is zero, this function chooses a convenient way
to return the value.
This function returns an rtx for where the value is to be found.
If VALUE is nonzero, VALUE is returned. */
rtx
emit_library_call_value
VPARAMS
((
rtx
orgfun
,
rtx
value
,
int
no_queue
,
enum
machine_mode
outmode
,
int
nargs
,
...))
{
#ifndef ANSI_PROTOTYPES
rtx
orgfun
;
rtx
value
;
int
no_queue
;
enum
machine_mode
outmode
;
int
nargs
;
#endif
va_list
p
;
VA_START
(
p
,
nargs
);
#ifndef ANSI_PROTOTYPES
orgfun
=
va_arg
(
p
,
rtx
);
value
=
va_arg
(
p
,
rtx
);
no_queue
=
va_arg
(
p
,
int
);
outmode
=
va_arg
(
p
,
enum
machine_mode
);
nargs
=
va_arg
(
p
,
int
);
#endif
value
=
emit_library_call_value_1
(
1
,
orgfun
,
value
,
no_queue
,
outmode
,
nargs
,
p
);
va_end
(
p
);
return
value
;
}
}
#if 0
#if 0
...
...
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