simple calls.c cleanups
Jan Hubicka
hubicka@atrey.karlin.mff.cuni.cz
Thu Mar 30 03:48:00 GMT 2000
Hi
This code contains simple cleanups. It breaks out the attributes detection
and code integration from expand_call as well as convert number of variables
to flags (this simplifies function calling at some places too).
While implementing it I found that we don't support nothrow and malloc
attributes at the fuction types. Is that some kind of design decision
or just omision?
I think all attributes allowed for functions ought to be useable for
indirect calls too.
Honza
Wed Mar 29 21:32:33 CEST 2000 Jan Hubicka <jh@suse.cz>
* calls.c (ECF_MALLOC, ECF_MAY_BE_ALLOCA, ECF_RETURNS_TWICE,
ECF_LONGJMP, ECF_FORK_OR_EXEC): New constants.
(ECF_IS_CONST): Rename to ECF_CONST.
(special_function_p): Make static, change interface.
(flags_from_decl_or_type, try_to_integrate): Break out from ...
(expand_call) ... here; convert number of variables to flags.
(emit_library_call_vlue_1): Likewise.
(setjmp_call_p): New function.
(initialize_argument_information): Accepts flags as argument;
return flags.
(precompute_arguments): Likewise.
* tree.h (special_function_p): Remove.
(setjmp_call_p): Add prototype.
Wed Mar 29 21:37:22 CEST 2000 Jan Hubicka <jh@suse.cz>
* optimize.c (calls_setjmp_p): Use setjmp_call_p instead of
special_function_p.
*** tree.h.ooo Wed Mar 29 20:26:10 2000
--- tree.h Wed Mar 29 21:03:13 2000
*************** extern struct rtx_def *emit_line_note P
*** 2543,2550 ****
extern struct rtx_def *emit_line_note_force PARAMS ((const char *, int));
/* In calls.c */
! extern void special_function_p PARAMS ((tree, int *, int *,
! int *, int *, int *));
/* In c-typeck.c */
extern int mark_addressable PARAMS ((tree));
--- 2543,2551 ----
extern struct rtx_def *emit_line_note_force PARAMS ((const char *, int));
/* In calls.c */
!
! /* Flags used by special_function_p. */
! extern int setjmp_call_p PARAMS ((tree));
/* In c-typeck.c */
extern int mark_addressable PARAMS ((tree));
*** cp/optimize.c.ooo Wed Mar 29 20:57:39 2000
--- cp/optimize.c Wed Mar 29 21:03:05 2000
*************** calls_setjmp_r (tp, walk_subtrees, data)
*** 758,767 ****
if (TREE_CODE (*tp) != FUNCTION_DECL)
return NULL_TREE;
! special_function_p (*tp, &setjmp_p, &longjmp_p, &fork_or_exec_p, &malloc_p,
! &alloca_p);
!
! return setjmp_p ? *tp : NULL_TREE;
}
/* Returns non-zero if FN calls `setjmp' or some other function that
--- 758,764 ----
if (TREE_CODE (*tp) != FUNCTION_DECL)
return NULL_TREE;
! return setjmp_call_p (tp);
}
/* Returns non-zero if FN calls `setjmp' or some other function that
*** calls.c.ooo Wed Mar 29 20:09:09 2000
--- calls.c Wed Mar 29 21:39:12 2000
*************** int stack_arg_under_construction;
*** 150,158 ****
static int calls_function PARAMS ((tree, int));
static int calls_function_1 PARAMS ((tree, int));
! #define ECF_IS_CONST 1
! #define ECF_NOTHROW 2
! #define ECF_SIBCALL 4
static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT, rtx,
rtx, int, rtx, int));
--- 150,174 ----
static int calls_function PARAMS ((tree, int));
static int calls_function_1 PARAMS ((tree, int));
! /* Nonzero if this is a call to a `const' function. */
! #define ECF_CONST 1
! /* Nonzero if this is a call to a `volatile' function. */
! #define ECF_NORETURN 2
! /* Nonzero if this is a call to malloc or a related function. */
! #define ECF_MALLOC 4
! /* Nonzero if it is plausible that this is a call to alloca. */
! #define ECF_MAY_BE_ALLOCA 8
! /* Nonzero if this is a call to a function that won't throw an exception. */
! #define ECF_NOTHROW 16
! /* Nonzero if this is a call to setjmp or a related function. */
! #define ECF_RETURNS_TWICE 32
! /* Nonzero if this is a call to `longjmp'. */
! #define ECF_LONGJMP 64
! /* Nonzero if this is a syscall that makes a new process in the image of
! the current one. */
! #define ECF_FORK_OR_EXEC 128
! #define ECF_SIBCALL 256
!
static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT, rtx,
rtx, int, rtx, int));
*************** static int libfunc_nothrow PARAMS ((rt
*** 188,193 ****
--- 204,213 ----
static rtx emit_library_call_value_1 PARAMS ((int, rtx, rtx, int,
enum machine_mode,
int, va_list));
+ static int special_function_p PARAMS ((tree, int));
+ static int flags_from_decl_or_type PARAMS ((tree));
+ static rtx try_to_integrate PARAMS ((tree, tree, rtx,
+ int, tree, rtx));
#ifdef REG_PARM_STACK_SPACE
static rtx save_fixed_argument_area PARAMS ((int, rtx, int *, int *));
*************** prepare_call_address (funexp, fndecl, ca
*** 401,409 ****
We restore `inhibit_defer_pop' to that value.
CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that
! denote registers used by the called function.
!
! IS_CONST is true if this is a `const' call. */
static void
emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
--- 421,427 ----
We restore `inhibit_defer_pop' to that value.
CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that
! denote registers used by the called function. */
static void
emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
*************** emit_call_1 (funexp, fndecl, funtype, st
*** 553,559 ****
CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
/* If this is a const call, then set the insn's unchanging bit. */
! if (ecf_flags & ECF_IS_CONST)
CONST_CALL_P (call_insn) = 1;
/* If this call can't throw, attach a REG_EH_REGION reg note to that
--- 571,577 ----
CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
/* If this is a const call, then set the insn's unchanging bit. */
! if (ecf_flags & ECF_CONST)
CONST_CALL_P (call_insn) = 1;
/* If this call can't throw, attach a REG_EH_REGION reg note to that
*************** emit_call_1 (funexp, fndecl, funtype, st
*** 595,601 ****
if (rounded_stack_size != 0)
{
if (flag_defer_pop && inhibit_defer_pop == 0
! && !(ecf_flags & ECF_IS_CONST))
pending_stack_adjust += rounded_stack_size;
else
adjust_stack (rounded_stack_size_rtx);
--- 613,619 ----
if (rounded_stack_size != 0)
{
if (flag_defer_pop && inhibit_defer_pop == 0
! && !(ecf_flags & ECF_CONST))
pending_stack_adjust += rounded_stack_size;
else
adjust_stack (rounded_stack_size_rtx);
*************** emit_call_1 (funexp, fndecl, funtype, st
*** 622,654 ****
For example, if the function might return more than one time (setjmp), then
set RETURNS_TWICE to a nonzero value.
! Similarly set IS_LONGJMP for if the function is in the longjmp family.
! Set IS_MALLOC for any of the standard memory allocation functions which
allocate from the heap.
Set MAY_BE_ALLOCA for any memory allocation function that might allocate
space from the stack such as alloca. */
! void
! special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
! is_malloc, may_be_alloca)
tree fndecl;
! int *returns_twice;
! int *is_longjmp;
! int *fork_or_exec;
! int *is_malloc;
! int *may_be_alloca;
! {
! *returns_twice = 0;
! *is_longjmp = 0;
! *fork_or_exec = 0;
! *may_be_alloca = 0;
!
! /* The function decl may have the `malloc' attribute. */
! *is_malloc = fndecl && DECL_IS_MALLOC (fndecl);
!
! if (! *is_malloc
&& fndecl && DECL_NAME (fndecl)
&& IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
/* Exclude functions not at the file scope, or not `extern',
--- 640,659 ----
For example, if the function might return more than one time (setjmp), then
set RETURNS_TWICE to a nonzero value.
! Similarly set LONGJMP for if the function is in the longjmp family.
! Set MALLOC for any of the standard memory allocation functions which
allocate from the heap.
Set MAY_BE_ALLOCA for any memory allocation function that might allocate
space from the stack such as alloca. */
! static int
! special_function_p (fndecl, flags)
tree fndecl;
! int flags;
! {
! if (! (flags & ECF_MALLOC)
&& fndecl && DECL_NAME (fndecl)
&& IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
/* Exclude functions not at the file scope, or not `extern',
*************** special_function_p (fndecl, returns_twic
*** 662,674 ****
/* We assume that alloca will always be called by name. It
makes no sense to pass it as a pointer-to-function to
anything that does not understand its behavior. */
! *may_be_alloca
! = (((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
! && name[0] == 'a'
! && ! strcmp (name, "alloca"))
! || (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16
! && name[0] == '_'
! && ! strcmp (name, "__builtin_alloca"))));
/* Disregard prefix _, __ or __x. */
if (name[0] == '_')
--- 667,679 ----
/* We assume that alloca will always be called by name. It
makes no sense to pass it as a pointer-to-function to
anything that does not understand its behavior. */
! if (((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
! && name[0] == 'a'
! && ! strcmp (name, "alloca"))
! || (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16
! && name[0] == '_'
! && ! strcmp (name, "__builtin_alloca"))))
! flags |= ECF_MAY_BE_ALLOCA;
/* Disregard prefix _, __ or __x. */
if (name[0] == '_')
*************** special_function_p (fndecl, returns_twic
*** 683,709 ****
if (tname[0] == 's')
{
! *returns_twice
! = ((tname[1] == 'e'
! && (! strcmp (tname, "setjmp")
! || ! strcmp (tname, "setjmp_syscall")))
! || (tname[1] == 'i'
! && ! strcmp (tname, "sigsetjmp"))
! || (tname[1] == 'a'
! && ! strcmp (tname, "savectx")));
if (tname[1] == 'i'
&& ! strcmp (tname, "siglongjmp"))
! *is_longjmp = 1;
}
else if ((tname[0] == 'q' && tname[1] == 's'
&& ! strcmp (tname, "qsetjmp"))
|| (tname[0] == 'v' && tname[1] == 'f'
&& ! strcmp (tname, "vfork")))
! *returns_twice = 1;
else if (tname[0] == 'l' && tname[1] == 'o'
&& ! strcmp (tname, "longjmp"))
! *is_longjmp = 1;
else if ((tname[0] == 'f' && tname[1] == 'o'
&& ! strcmp (tname, "fork"))
--- 688,715 ----
if (tname[0] == 's')
{
! if ((tname[1] == 'e'
! && (! strcmp (tname, "setjmp")
! || ! strcmp (tname, "setjmp_syscall")))
! || (tname[1] == 'i'
! && ! strcmp (tname, "sigsetjmp"))
! || (tname[1] == 'a'
! && ! strcmp (tname, "savectx")))
! flags |= ECF_RETURNS_TWICE;
!
if (tname[1] == 'i'
&& ! strcmp (tname, "siglongjmp"))
! flags |= ECF_LONGJMP;
}
else if ((tname[0] == 'q' && tname[1] == 's'
&& ! strcmp (tname, "qsetjmp"))
|| (tname[0] == 'v' && tname[1] == 'f'
&& ! strcmp (tname, "vfork")))
! flags |= ECF_RETURNS_TWICE;
else if (tname[0] == 'l' && tname[1] == 'o'
&& ! strcmp (tname, "longjmp"))
! flags |= ECF_LONGJMP;
else if ((tname[0] == 'f' && tname[1] == 'o'
&& ! strcmp (tname, "fork"))
*************** special_function_p (fndecl, returns_twic
*** 717,723 ****
&& (tname[5] == '\0'
|| ((tname[5] == 'p' || tname[5] == 'e')
&& tname[6] == '\0'))))
! *fork_or_exec = 1;
/* Do not add any more malloc-like functions to this list,
instead mark them as malloc functions using the malloc attribute.
--- 723,729 ----
&& (tname[5] == '\0'
|| ((tname[5] == 'p' || tname[5] == 'e')
&& tname[6] == '\0'))))
! flags |= ECF_FORK_OR_EXEC;
/* Do not add any more malloc-like functions to this list,
instead mark them as malloc functions using the malloc attribute.
*************** special_function_p (fndecl, returns_twic
*** 730,739 ****
&& (! strcmp (tname, "malloc")
|| ! strcmp (tname, "calloc")
|| ! strcmp (tname, "strdup")))
! *is_malloc = 1;
}
}
/* Precompute all register parameters as described by ARGS, storing values
into fields within the ARGS array.
--- 736,781 ----
&& (! strcmp (tname, "malloc")
|| ! strcmp (tname, "calloc")
|| ! strcmp (tname, "strdup")))
! flags |= ECF_MALLOC;
! }
! return flags;
! }
!
! /* Return nonzero when tree represent call to longjmp. */
! int
! setjmp_call_p (fndecl)
! tree fndecl;
! {
! return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
! }
!
! /* Detect flags (function attributes) from the function type node. */
! static int
! flags_from_decl_or_type (exp)
! tree exp;
! {
! int flags = 0;
! /* ??? We can't set IS_MALLOC for function types? */
! if (DECL_P (exp))
! {
! /* The function exp may have the `malloc' attribute. */
! if (DECL_P (exp) && DECL_IS_MALLOC (exp))
! flags |= ECF_MALLOC;
!
! if (TREE_NOTHROW (exp))
! flags |= ECF_NOTHROW;
}
+
+ if (TREE_READONLY (exp) && !TREE_THIS_VOLATILE (exp))
+ flags |= ECF_CONST;
+
+ if (TREE_THIS_VOLATILE (exp))
+ flags |= ECF_NORETURN;
+
+ return flags;
}
+
/* Precompute all register parameters as described by ARGS, storing values
into fields within the ARGS array.
*************** store_unaligned_arguments_into_pseudos (
*** 996,1009 ****
OLD_STACK_LEVEL is a pointer to an rtx which olds the old stack level
and may be modified by this routine.
! OLD_PENDING_ADJ, MUST_PREALLOCATE and IS_CONST are pointers to integer
flags which may may be modified by this routine. */
static void
initialize_argument_information (num_actuals, args, args_size, n_named_args,
actparms, fndecl, args_so_far,
reg_parm_stack_space, old_stack_level,
! old_pending_adj, must_preallocate, is_const,
ecf_flags)
int num_actuals ATTRIBUTE_UNUSED;
struct arg_data *args;
--- 1038,1051 ----
OLD_STACK_LEVEL is a pointer to an rtx which olds the old stack level
and may be modified by this routine.
! OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer
flags which may may be modified by this routine. */
static void
initialize_argument_information (num_actuals, args, args_size, n_named_args,
actparms, fndecl, args_so_far,
reg_parm_stack_space, old_stack_level,
! old_pending_adj, must_preallocate, flags,
ecf_flags)
int num_actuals ATTRIBUTE_UNUSED;
struct arg_data *args;
*************** initialize_argument_information (num_act
*** 1016,1023 ****
rtx *old_stack_level;
int *old_pending_adj;
int *must_preallocate;
! int *is_const;
! int ecf_flags;
{
/* 1 if scanning parms front to back, -1 if scanning back to front. */
int inc;
--- 1058,1065 ----
rtx *old_stack_level;
int *old_pending_adj;
int *must_preallocate;
! int *flags;
! int ecf_flags ATTRIBUTE_UNUSED;
{
/* 1 if scanning parms front to back, -1 if scanning back to front. */
int inc;
*************** initialize_argument_information (num_act
*** 1160,1166 ****
MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
store_expr (args[i].tree_value, copy, 0);
! *is_const = 0;
args[i].tree_value = build1 (ADDR_EXPR,
build_pointer_type (type),
--- 1202,1208 ----
MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
store_expr (args[i].tree_value, copy, 0);
! *flags &= ~ECF_CONST;
args[i].tree_value = build1 (ADDR_EXPR,
build_pointer_type (type),
*************** initialize_argument_information (num_act
*** 1219,1225 ****
/* If this is an addressable type, we cannot pre-evaluate it. Thus,
we cannot consider this function call constant. */
if (TREE_ADDRESSABLE (type))
! *is_const = 0;
/* Compute the stack-size of this argument. */
if (args[i].reg == 0 || args[i].partial != 0
--- 1261,1267 ----
/* If this is an addressable type, we cannot pre-evaluate it. Thus,
we cannot consider this function call constant. */
if (TREE_ADDRESSABLE (type))
! *flags &= ~ECF_CONST;
/* Compute the stack-size of this argument. */
if (args[i].reg == 0 || args[i].partial != 0
*************** compute_argument_block_size (reg_parm_st
*** 1359,1365 ****
/* Precompute parameters as needed for a function call.
! IS_CONST indicates the target function is a pure function.
MUST_PREALLOCATE indicates that we must preallocate stack space for
any stack arguments.
--- 1401,1407 ----
/* Precompute parameters as needed for a function call.
! FLAGS is mask of ECF_* constants.
MUST_PREALLOCATE indicates that we must preallocate stack space for
any stack arguments.
*************** compute_argument_block_size (reg_parm_st
*** 1372,1379 ****
ARGS_SIZE contains information about the size of the arg list. */
static void
! precompute_arguments (is_const, must_preallocate, num_actuals, args, args_size)
! int is_const;
int must_preallocate;
int num_actuals;
struct arg_data *args;
--- 1414,1421 ----
ARGS_SIZE contains information about the size of the arg list. */
static void
! precompute_arguments (flags, must_preallocate, num_actuals, args, args_size)
! int flags;
int must_preallocate;
int num_actuals;
struct arg_data *args;
*************** precompute_arguments (is_const, must_pre
*** 1395,1401 ****
which have already been stored into the stack. */
for (i = 0; i < num_actuals; i++)
! if (is_const
|| ((args_size->var != 0 || args_size->constant != 0)
&& calls_function (args[i].tree_value, 1))
|| (must_preallocate
--- 1437,1443 ----
which have already been stored into the stack. */
for (i = 0; i < num_actuals; i++)
! if ((flags & ECF_CONST)
|| ((args_size->var != 0 || args_size->constant != 0)
&& calls_function (args[i].tree_value, 1))
|| (must_preallocate
*************** load_register_parameters (args, num_actu
*** 1695,1700 ****
--- 1737,1858 ----
}
}
+ /* Try to integreate function. See expand_inline_function for documentation
+ about the parameters. */
+
+ static rtx
+ try_to_integrate (fndecl, actparms, target, ignore, exp, structure_value_addr)
+ tree fndecl;
+ tree actparms;
+ rtx target;
+ int ignore;
+ tree exp;
+ rtx structure_value_addr;
+ {
+ rtx temp;
+ rtx before_call;
+ int i;
+ rtx old_stack_level = 0;
+ int reg_parm_stack_space;
+
+ #ifdef REG_PARM_STACK_SPACE
+ #ifdef MAYBE_REG_PARM_STACK_SPACE
+ reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
+ #else
+ reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+ #endif
+ #endif
+
+ before_call = get_last_insn ();
+
+ temp = expand_inline_function (fndecl, actparms, target,
+ ignore, TREE_TYPE (exp),
+ structure_value_addr);
+
+ /* If inlining succeeded, return. */
+ if (temp != (rtx) (HOST_WIDE_INT) - 1)
+ {
+ if (ACCUMULATE_OUTGOING_ARGS)
+ {
+ /* If the outgoing argument list must be preserved, push
+ the stack before executing the inlined function if it
+ makes any calls. */
+
+ for (i = reg_parm_stack_space - 1; i >= 0; i--)
+ if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0)
+ break;
+
+ if (stack_arg_under_construction || i >= 0)
+ {
+ rtx first_insn
+ = before_call ? NEXT_INSN (before_call) : get_insns ();
+ rtx insn = NULL_RTX, seq;
+
+ /* Look for a call in the inline function code.
+ If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is
+ nonzero then there is a call and it is not necessary
+ to scan the insns. */
+
+ if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0)
+ for (insn = first_insn; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == CALL_INSN)
+ break;
+
+ if (insn)
+ {
+ /* Reserve enough stack space so that the largest
+ argument list of any function call in the inline
+ function does not overlap the argument list being
+ evaluated. This is usually an overestimate because
+ allocate_dynamic_stack_space reserves space for an
+ outgoing argument list in addition to the requested
+ space, but there is no way to ask for stack space such
+ that an argument list of a certain length can be
+ safely constructed.
+
+ Add the stack space reserved for register arguments, if
+ any, in the inline function. What is really needed is the
+ largest value of reg_parm_stack_space in the inline
+ function, but that is not available. Using the current
+ value of reg_parm_stack_space is wrong, but gives
+ correct results on all supported machines. */
+
+ int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size
+ + reg_parm_stack_space);
+
+ start_sequence ();
+ emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+ allocate_dynamic_stack_space (GEN_INT (adjust),
+ NULL_RTX, BITS_PER_UNIT);
+ seq = get_insns ();
+ end_sequence ();
+ emit_insns_before (seq, first_insn);
+ emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
+ }
+ }
+ }
+
+ /* If the result is equivalent to TARGET, return TARGET to simplify
+ checks in store_expr. They can be equivalent but not equal in the
+ case of a function that returns BLKmode. */
+ if (temp != target && rtx_equal_p (temp, target))
+ return target;
+ return temp;
+ }
+
+ /* If inlining failed, mark FNDECL as needing to be compiled
+ separately after all. If function was declared inline,
+ give a warning. */
+ if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
+ && optimize > 0 && !TREE_ADDRESSABLE (fndecl))
+ {
+ warning_with_decl (fndecl, "inlining failed in call to `%s'");
+ warning ("called from here");
+ }
+ mark_addressable (fndecl);
+ return NULL_RTX;
+ }
+
/* Generate all the code for a function call
and return an rtx for its value.
Store the value in TARGET (specified as an rtx) if convenient.
*************** expand_call (exp, target, ignore)
*** 1726,1732 ****
or 0 if the function is computed (not known by name). */
tree fndecl = 0;
char *name = 0;
- rtx before_call;
rtx insn;
int try_tail_call;
int pass;
--- 1884,1889 ----
*************** expand_call (exp, target, ignore)
*** 1785,1810 ****
(on machines that lack push insns), or 0 if space not preallocated. */
rtx argblock = 0;
! /* Nonzero if it is plausible that this is a call to alloca. */
! int may_be_alloca;
! /* Nonzero if this is a call to malloc or a related function. */
! int is_malloc;
! /* Nonzero if this is a call to setjmp or a related function. */
! int returns_twice;
! /* Nonzero if this is a call to `longjmp'. */
! int is_longjmp;
! /* Nonzero if this is a syscall that makes a new process in the image of
! the current one. */
! int fork_or_exec;
/* Nonzero if this is a call to an inline function. */
int is_integrable = 0;
- /* Nonzero if this is a call to a `const' function.
- Note that only explicitly named functions are handled as `const' here. */
- int is_const = 0;
- /* Nonzero if this is a call to a `volatile' function. */
- int is_volatile = 0;
- /* Nonzero if this is a call to a function that won't throw an exception. */
- int nothrow = TREE_NOTHROW (exp);
#ifdef REG_PARM_STACK_SPACE
/* Define the boundary of the register parm stack space that needs to be
save, if any. */
--- 1942,1951 ----
(on machines that lack push insns), or 0 if space not preallocated. */
rtx argblock = 0;
! /* Mask of ECF_ flags. */
! int flags = 0;
/* Nonzero if this is a call to an inline function. */
int is_integrable = 0;
#ifdef REG_PARM_STACK_SPACE
/* Define the boundary of the register parm stack space that needs to be
save, if any. */
*************** expand_call (exp, target, ignore)
*** 1831,1836 ****
--- 1972,1981 ----
if (current_function_check_memory_usage)
target = 0;
+ /* See if this is "nothrow" function call. */
+ if (TREE_NOTHROW (exp))
+ flags |= ECF_NOTHROW;
+
/* See if we can find a DECL-node for the actual function.
As a result, decide whether this is a call to an integrable function. */
*************** expand_call (exp, target, ignore)
*** 1864,1887 ****
mark_addressable (fndecl);
}
! if (TREE_READONLY (fndecl) && ! TREE_THIS_VOLATILE (fndecl)
! && TYPE_MODE (TREE_TYPE (exp)) != VOIDmode)
! is_const = 1;
!
! if (TREE_THIS_VOLATILE (fndecl))
! is_volatile = 1;
!
! if (TREE_NOTHROW (fndecl))
! nothrow = 1;
}
}
/* If we don't have specific function to call, see if we have a
! constant or `noreturn' function from the type. */
if (fndecl == 0)
{
! is_const = TREE_READONLY (TREE_TYPE (TREE_TYPE (p)));
! is_volatile = TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (p)));
}
#ifdef REG_PARM_STACK_SPACE
--- 2009,2023 ----
mark_addressable (fndecl);
}
! flags |= flags_from_decl_or_type (fndecl);
}
}
/* If we don't have specific function to call, see if we have a
! attributes set in the type. */
if (fndecl == 0)
{
! flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
}
#ifdef REG_PARM_STACK_SPACE
*************** expand_call (exp, target, ignore)
*** 1908,1914 ****
if (aggregate_value_p (exp))
{
/* This call returns a big structure. */
! is_const = 0;
#ifdef PCC_STATIC_STRUCT_RETURN
{
--- 2044,2050 ----
if (aggregate_value_p (exp))
{
/* This call returns a big structure. */
! flags &= ~ECF_CONST;
#ifdef PCC_STATIC_STRUCT_RETURN
{
*************** expand_call (exp, target, ignore)
*** 1959,2053 ****
if (is_integrable)
{
! rtx temp;
!
! before_call = get_last_insn ();
!
! temp = expand_inline_function (fndecl, actparms, target,
! ignore, TREE_TYPE (exp),
! structure_value_addr);
!
! /* If inlining succeeded, return. */
! if (temp != (rtx) (HOST_WIDE_INT) -1)
! {
! if (ACCUMULATE_OUTGOING_ARGS)
! {
! /* If the outgoing argument list must be preserved, push
! the stack before executing the inlined function if it
! makes any calls. */
!
! for (i = reg_parm_stack_space - 1; i >= 0; i--)
! if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0)
! break;
!
! if (stack_arg_under_construction || i >= 0)
! {
! rtx first_insn
! = before_call ? NEXT_INSN (before_call) : get_insns ();
! rtx insn = NULL_RTX, seq;
!
! /* Look for a call in the inline function code.
! If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is
! nonzero then there is a call and it is not necessary
! to scan the insns. */
!
! if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0)
! for (insn = first_insn; insn; insn = NEXT_INSN (insn))
! if (GET_CODE (insn) == CALL_INSN)
! break;
!
! if (insn)
! {
! /* Reserve enough stack space so that the largest
! argument list of any function call in the inline
! function does not overlap the argument list being
! evaluated. This is usually an overestimate because
! allocate_dynamic_stack_space reserves space for an
! outgoing argument list in addition to the requested
! space, but there is no way to ask for stack space such
! that an argument list of a certain length can be
! safely constructed.
!
! Add the stack space reserved for register arguments, if
! any, in the inline function. What is really needed is the
! largest value of reg_parm_stack_space in the inline
! function, but that is not available. Using the current
! value of reg_parm_stack_space is wrong, but gives
! correct results on all supported machines. */
!
! int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size
! + reg_parm_stack_space);
!
! start_sequence ();
! emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
! allocate_dynamic_stack_space (GEN_INT (adjust),
! NULL_RTX, BITS_PER_UNIT);
! seq = get_insns ();
! end_sequence ();
! emit_insns_before (seq, first_insn);
! emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
! }
! }
! }
!
! /* If the result is equivalent to TARGET, return TARGET to simplify
! checks in store_expr. They can be equivalent but not equal in the
! case of a function that returns BLKmode. */
! if (temp != target && rtx_equal_p (temp, target))
! return target;
! return temp;
! }
!
! /* If inlining failed, mark FNDECL as needing to be compiled
! separately after all. If function was declared inline,
! give a warning. */
! if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
! && optimize > 0 && ! TREE_ADDRESSABLE (fndecl))
! {
! warning_with_decl (fndecl, "inlining failed in call to `%s'");
! warning ("called from here");
! }
! mark_addressable (fndecl);
}
currently_expanding_call++;
--- 2095,2105 ----
if (is_integrable)
{
! rtx temp = try_to_integrate (fndecl, actparms, target,
! ignore, TREE_TYPE (exp),
! structure_value_addr);
! if (temp)
! return temp;
}
currently_expanding_call++;
*************** expand_call (exp, target, ignore)
*** 2163,2172 ****
/* See if this is a call to a function that can return more than once
or a call to longjmp or malloc. */
! special_function_p (fndecl, &returns_twice, &is_longjmp, &fork_or_exec,
! &is_malloc, &may_be_alloca);
! if (may_be_alloca)
current_function_calls_alloca = 1;
/* Operand 0 is a pointer-to-function; get the type of the function. */
--- 2215,2223 ----
/* See if this is a call to a function that can return more than once
or a call to longjmp or malloc. */
! flags |= special_function_p (fndecl, flags);
! if (flags & ECF_MAY_BE_ALLOCA)
current_function_calls_alloca = 1;
/* Operand 0 is a pointer-to-function; get the type of the function. */
*************** expand_call (exp, target, ignore)
*** 2226,2232 ****
}
/* Other state variables that we must reinitialize each time
! through the loop (that are not initialized by the loop itself. */
argblock = 0;
call_fusage = 0;
--- 2277,2283 ----
}
/* Other state variables that we must reinitialize each time
! through the loop (that are not initialized by the loop itself). */
argblock = 0;
call_fusage = 0;
*************** expand_call (exp, target, ignore)
*** 2238,2244 ****
/* When calling a const function, we must pop the stack args right away,
so that the pop is deleted or moved with the call. */
! if (is_const)
NO_DEFER_POP;
/* Don't let pending stack adjusts add up to too much.
--- 2289,2295 ----
/* When calling a const function, we must pop the stack args right away,
so that the pop is deleted or moved with the call. */
! if (flags & ECF_CONST)
NO_DEFER_POP;
/* Don't let pending stack adjusts add up to too much.
*************** expand_call (exp, target, ignore)
*** 2246,2256 ****
this might be a call to alloca or if we are expanding a sibling
call sequence. */
if (pending_stack_adjust >= 32
! || (pending_stack_adjust > 0 && may_be_alloca)
|| pass == 0)
do_pending_stack_adjust ();
! if (profile_arc_flag && fork_or_exec)
{
/* A fork duplicates the profile information, and an exec discards
it. We can't rely on fork/exec to be paired. So write out the
--- 2297,2307 ----
this might be a call to alloca or if we are expanding a sibling
call sequence. */
if (pending_stack_adjust >= 32
! || (pending_stack_adjust > 0 && (flags & ECF_MAY_BE_ALLOCA))
|| pass == 0)
do_pending_stack_adjust ();
! if (profile_arc_flag && (flags & ECF_FORK_OR_EXEC))
{
/* A fork duplicates the profile information, and an exec discards
it. We can't rely on fork/exec to be paired. So write out the
*************** expand_call (exp, target, ignore)
*** 2343,2349 ****
n_named_args, actparms, fndecl,
&args_so_far, reg_parm_stack_space,
&old_stack_level, &old_pending_adj,
! &must_preallocate, &is_const,
(pass == 0) ? ECF_SIBCALL : 0);
#ifdef FINAL_REG_PARM_STACK_SPACE
--- 2394,2400 ----
n_named_args, actparms, fndecl,
&args_so_far, reg_parm_stack_space,
&old_stack_level, &old_pending_adj,
! &must_preallocate, &flags,
(pass == 0) ? ECF_SIBCALL : 0);
#ifdef FINAL_REG_PARM_STACK_SPACE
*************** expand_call (exp, target, ignore)
*** 2360,2366 ****
Also do not make a sibling call. */
! is_const = 0;
must_preallocate = 1;
sibcall_failure = 1;
}
--- 2411,2417 ----
Also do not make a sibling call. */
! flags &= ~ECF_CONST;
must_preallocate = 1;
sibcall_failure = 1;
}
*************** expand_call (exp, target, ignore)
*** 2409,2420 ****
structure_value_addr = copy_to_reg (structure_value_addr);
/* Precompute any arguments as needed. */
! precompute_arguments (is_const, must_preallocate, num_actuals,
args, &args_size);
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
! if (is_const || is_malloc)
start_sequence ();
/* If we have no actual push instructions, or shouldn't use them,
--- 2460,2471 ----
structure_value_addr = copy_to_reg (structure_value_addr);
/* Precompute any arguments as needed. */
! precompute_arguments (flags, must_preallocate, num_actuals,
args, &args_size);
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
! if (flags & (ECF_CONST || ECF_MALLOC))
start_sequence ();
/* If we have no actual push instructions, or shouldn't use them,
*************** expand_call (exp, target, ignore)
*** 2595,2601 ****
{
/* When the stack adjustment is pending, we get better code
by combining the adjustments. */
! if (pending_stack_adjust && ! is_const
&& ! inhibit_defer_pop)
{
args_size.constant = (unadjusted_args_size
--- 2646,2652 ----
{
/* When the stack adjustment is pending, we get better code
by combining the adjustments. */
! if (pending_stack_adjust && ! (flags & ECF_CONST)
&& ! inhibit_defer_pop)
{
args_size.constant = (unadjusted_args_size
*************** expand_call (exp, target, ignore)
*** 2659,2665 ****
for (i = 0; i < num_actuals; i++)
if (args[i].reg == 0 || args[i].pass_on_stack)
! store_one_arg (&args[i], argblock, may_be_alloca,
args_size.var != 0, reg_parm_stack_space);
/* If we have a parm that is passed in registers but not in memory
--- 2710,2716 ----
for (i = 0; i < num_actuals; i++)
if (args[i].reg == 0 || args[i].pass_on_stack)
! store_one_arg (&args[i], argblock, flags & ECF_MAY_BE_ALLOCA,
args_size.var != 0, reg_parm_stack_space);
/* If we have a parm that is passed in registers but not in memory
*************** expand_call (exp, target, ignore)
*** 2674,2680 ****
if (reg_parm_seen)
for (i = 0; i < num_actuals; i++)
if (args[i].partial != 0 && ! args[i].pass_on_stack)
! store_one_arg (&args[i], argblock, may_be_alloca,
args_size.var != 0, reg_parm_stack_space);
#ifdef PREFERRED_STACK_BOUNDARY
--- 2725,2731 ----
if (reg_parm_seen)
for (i = 0; i < num_actuals; i++)
if (args[i].partial != 0 && ! args[i].pass_on_stack)
! store_one_arg (&args[i], argblock, flags & ECF_MAY_BE_ALLOCA,
args_size.var != 0, reg_parm_stack_space);
#ifdef PREFERRED_STACK_BOUNDARY
*************** expand_call (exp, target, ignore)
*** 2748,2762 ****
emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size,
args_size.constant, struct_value_size,
next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
! ((is_const ? ECF_IS_CONST : 0)
! | (nothrow ? ECF_NOTHROW : 0)
! | (pass == 0 ? ECF_SIBCALL : 0)));
/* If call is cse'able, make appropriate pair of reg-notes around it.
Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because
we have no way to move such values into a pseudo register. */
! if (is_const && valreg != 0 && GET_CODE (valreg) != PARALLEL)
{
rtx note = 0;
rtx temp = gen_reg_rtx (GET_MODE (valreg));
--- 2799,2811 ----
emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size,
args_size.constant, struct_value_size,
next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
! flags | (pass == 0 ? ECF_SIBCALL : 0));
/* If call is cse'able, make appropriate pair of reg-notes around it.
Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because
we have no way to move such values into a pseudo register. */
! if ((flags & ECF_CONST) && valreg != 0 && GET_CODE (valreg) != PARALLEL)
{
rtx note = 0;
rtx temp = gen_reg_rtx (GET_MODE (valreg));
*************** expand_call (exp, target, ignore)
*** 2786,2792 ****
valreg = temp;
}
! else if (is_const)
{
/* Otherwise, just write out the sequence without a note. */
rtx insns = get_insns ();
--- 2835,2841 ----
valreg = temp;
}
! else if (flags & ECF_CONST)
{
/* Otherwise, just write out the sequence without a note. */
rtx insns = get_insns ();
*************** expand_call (exp, target, ignore)
*** 2794,2800 ****
end_sequence ();
emit_insns (insns);
}
! else if (is_malloc)
{
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx last, insns;
--- 2843,2849 ----
end_sequence ();
emit_insns (insns);
}
! else if (flags & ECF_MALLOC)
{
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx last, insns;
*************** expand_call (exp, target, ignore)
*** 2822,2828 ****
if nonvolatile values are live. For functions that cannot return,
inform flow that control does not fall through. */
! if (returns_twice || is_volatile || is_longjmp || pass == 0)
{
/* The barrier or NOTE_INSN_SETJMP note must be emitted
immediately after the CALL_INSN. Some ports emit more
--- 2871,2877 ----
if nonvolatile values are live. For functions that cannot return,
inform flow that control does not fall through. */
! if ((flags & (ECF_RETURNS_TWICE | ECF_NORETURN | ECF_LONGJMP)) || pass == 0)
{
/* The barrier or NOTE_INSN_SETJMP note must be emitted
immediately after the CALL_INSN. Some ports emit more
*************** expand_call (exp, target, ignore)
*** 2837,2843 ****
abort ();
}
! if (returns_twice)
{
emit_note_after (NOTE_INSN_SETJMP, last);
current_function_calls_setjmp = 1;
--- 2886,2892 ----
abort ();
}
! if (flags & ECF_RETURNS_TWICE)
{
emit_note_after (NOTE_INSN_SETJMP, last);
current_function_calls_setjmp = 1;
*************** expand_call (exp, target, ignore)
*** 2847,2853 ****
emit_barrier_after (last);
}
! if (is_longjmp)
current_function_calls_longjmp = 1, sibcall_failure = 1;
/* If this function is returning into a memory location marked as
--- 2896,2902 ----
emit_barrier_after (last);
}
! if (flags & ECF_LONGJMP)
current_function_calls_longjmp = 1, sibcall_failure = 1;
/* If this function is returning into a memory location marked as
*************** expand_call (exp, target, ignore)
*** 3004,3010 ****
Check for the handler slots since we might not have a save area
for non-local gotos. */
! if (may_be_alloca && nonlocal_goto_handler_slots != 0)
emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
pop_temp_slots ();
--- 3053,3059 ----
Check for the handler slots since we might not have a save area
for non-local gotos. */
! if ((flags & ECF_MAY_BE_ALLOCA) && nonlocal_goto_handler_slots != 0)
emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
pop_temp_slots ();
*************** emit_library_call_value_1 (retval, orgfu
*** 3139,3147 ****
rtx mem_value = 0;
int pcc_struct_value = 0;
int struct_value_size = 0;
! int is_const;
int reg_parm_stack_space = 0;
- int nothrow;
int needed;
#ifdef REG_PARM_STACK_SPACE
--- 3188,3195 ----
rtx mem_value = 0;
int pcc_struct_value = 0;
int struct_value_size = 0;
! int flags = 0;
int reg_parm_stack_space = 0;
int needed;
#ifdef REG_PARM_STACK_SPACE
*************** emit_library_call_value_1 (retval, orgfu
*** 3163,3172 ****
#endif
#endif
! is_const = no_queue;
fun = orgfun;
! nothrow = libfunc_nothrow (fun);
#ifdef PREFERRED_STACK_BOUNDARY
/* Ensure current function's preferred stack boundary is at least
--- 3211,3222 ----
#endif
#endif
! if (no_queue)
! flags |= ECF_CONST;
fun = orgfun;
! if (libfunc_nothrow (fun))
! flags |= ECF_NOTHROW;
#ifdef PREFERRED_STACK_BOUNDARY
/* Ensure current function's preferred stack boundary is at least
*************** emit_library_call_value_1 (retval, orgfu
*** 3196,3202 ****
#endif
/* This call returns a big structure. */
! is_const = 0;
}
/* ??? Unfinished: must pass the memory address as an argument. */
--- 3246,3252 ----
#endif
/* This call returns a big structure. */
! flags &= ~ECF_CONST;
}
/* ??? Unfinished: must pass the memory address as an argument. */
*************** emit_library_call_value_1 (retval, orgfu
*** 3636,3644 ****
struct_value_size,
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
mem_value == 0 && outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
! old_inhibit_defer_pop + 1, call_fusage,
! ((is_const ? ECF_IS_CONST : 0)
! | (nothrow ? ECF_NOTHROW : 0)));
/* Now restore inhibit_defer_pop to its actual original value. */
OK_DEFER_POP;
--- 3686,3692 ----
struct_value_size,
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
mem_value == 0 && outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
! old_inhibit_defer_pop + 1, call_fusage, flags);
/* Now restore inhibit_defer_pop to its actual original value. */
OK_DEFER_POP;
*************** emit_library_call_value_1 (retval, orgfu
*** 3720,3726 ****
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,
--- 3768,3774 ----
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 flag ECF_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,
More information about the Gcc-patches
mailing list