/* Convert function calls to rtl insns, for GNU C compiler.
- Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1992, 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
#endif
static int calls_function PROTO((tree, int));
+static int calls_function_1 PROTO((tree, int));
static void emit_call_1 PROTO((rtx, tree, int, int, rtx, rtx, int,
rtx, int));
static void store_one_arg PROTO ((struct arg_data *, rtx, int, int,
arguments on the stack, but that is too difficult to compute, so we just
assume any function call might require the stack. */
+static tree calls_function_save_exprs;
+
static int
calls_function (exp, which)
tree exp;
int which;
{
+ int val;
+ calls_function_save_exprs = 0;
+ val = calls_function_1 (exp, which);
+ calls_function_save_exprs = 0;
+ return val;
+}
+
+static int
+calls_function_1 (exp, which)
+ tree exp;
+ int which;
+{
register int i;
int type = TREE_CODE_CLASS (TREE_CODE (exp));
int length = tree_code_length[(int) TREE_CODE (exp)];
case SAVE_EXPR:
if (SAVE_EXPR_RTL (exp) != 0)
return 0;
- break;
+ if (value_member (exp, calls_function_save_exprs))
+ return 0;
+ calls_function_save_exprs = tree_cons (NULL_TREE, exp,
+ calls_function_save_exprs);
+ return (TREE_OPERAND (exp, 0) != 0
+ && calls_function_1 (TREE_OPERAND (exp, 0), which));
case BLOCK:
{
for (local = BLOCK_VARS (exp); local; local = TREE_CHAIN (local))
if (DECL_INITIAL (local) != 0
- && calls_function (DECL_INITIAL (local), which))
+ && calls_function_1 (DECL_INITIAL (local), which))
return 1;
}
{
for (subblock = BLOCK_SUBBLOCKS (exp);
subblock;
subblock = TREE_CHAIN (subblock))
- if (calls_function (subblock, which))
+ if (calls_function_1 (subblock, which))
return 1;
}
return 0;
for (i = 0; i < length; i++)
if (TREE_OPERAND (exp, i) != 0
- && calls_function (TREE_OPERAND (exp, i), which))
+ && calls_function_1 (TREE_OPERAND (exp, i), which))
return 1;
return 0;
CUMULATIVE_ARGS args_so_far;
/* Nonzero if a reg parm has been scanned. */
int reg_parm_seen;
+ /* Nonzero if this is an indirect function call. */
+ int current_call_is_indirect = 0;
/* Nonzero if we must avoid push-insns in the args for this call.
If stack space is allocated for register parameters, but not by the
Use abstraction instead of setting TREE_ADDRESSABLE
directly. */
- if (DECL_INLINE (fndecl) && extra_warnings && !flag_no_inline)
+ if (DECL_INLINE (fndecl) && extra_warnings && warn_inline
+ && !flag_no_inline)
warning_with_decl (fndecl, "can't inline call to `%s' which was declared inline");
mark_addressable (fndecl);
}
adjust += reg_parm_stack_space;
#endif
start_sequence ();
- emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);
+ 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 ();
if (fndecl && DECL_NAME (fndecl))
name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+ /* On some machines (such as the PA) indirect calls have a different
+ calling convention than normal calls. FUNCTION_ARG in the target
+ description can look at current_call_is_indirect to determine which
+ calling convention to use. */
+ current_call_is_indirect = (fndecl == 0);
+#if 0
+ = TREE_CODE (TREE_OPERAND (exp, 0)) == NON_LVALUE_EXPR ? 1 : 0;
+#endif
+
#if 0
/* Unless it's a call to a specific function that isn't alloca,
if it has one argument, we must assume it might be alloca. */
if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type), type,
argpos < n_named_args))
{
- /* We make a copy of the object and pass the address to the function
- being called. */
- rtx copy;
-
- if (TYPE_SIZE (type) == 0
- || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+#ifdef FUNCTION_ARG_CALLEE_COPIES
+ if (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type), type,
+ argpos < n_named_args)
+ /* If it's in a register, we must make a copy of it too. */
+ /* ??? Is this a sufficient test? Is there a better one? */
+ && !(TREE_CODE (args[i].tree_value) == VAR_DECL
+ && REG_P (DECL_RTL (args[i].tree_value))))
{
- /* This is a variable-sized object. Make space on the stack
- for it. */
- rtx size_rtx = expr_size (TREE_VALUE (p));
-
- if (old_stack_level == 0)
- {
- emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
- old_pending_adj = pending_stack_adjust;
- pending_stack_adjust = 0;
- }
-
- copy = gen_rtx (MEM, BLKmode,
- allocate_dynamic_stack_space (size_rtx, NULL_RTX,
- TYPE_ALIGN (type)));
+ args[i].tree_value = build1 (ADDR_EXPR,
+ build_pointer_type (type),
+ args[i].tree_value);
+ type = build_pointer_type (type);
}
else
+#endif
{
- int size = int_size_in_bytes (type);
- copy = assign_stack_temp (TYPE_MODE (type), size, 1);
- }
+ /* We make a copy of the object and pass the address to the
+ function being called. */
+ rtx copy;
+
+ if (TYPE_SIZE (type) == 0
+ || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ {
+ /* This is a variable-sized object. Make space on the stack
+ for it. */
+ rtx size_rtx = expr_size (TREE_VALUE (p));
+
+ if (old_stack_level == 0)
+ {
+ emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+ old_pending_adj = pending_stack_adjust;
+ pending_stack_adjust = 0;
+ }
+
+ copy = gen_rtx (MEM, BLKmode,
+ allocate_dynamic_stack_space (size_rtx,
+ NULL_RTX,
+ TYPE_ALIGN (type)));
+ }
+ else
+ {
+ int size = int_size_in_bytes (type);
+ copy = assign_stack_temp (TYPE_MODE (type), size, 1);
+ }
- store_expr (args[i].tree_value, copy, 0);
+ store_expr (args[i].tree_value, copy, 0);
- args[i].tree_value = build1 (ADDR_EXPR, build_pointer_type (type),
- make_tree (type, copy));
- type = build_pointer_type (type);
+ args[i].tree_value = build1 (ADDR_EXPR,
+ build_pointer_type (type),
+ make_tree (type, copy));
+ type = build_pointer_type (type);
+ }
}
-#endif
+#endif /* FUNCTION_ARG_PASS_BY_REFERENCE */
mode = TYPE_MODE (type);
/* Get the function to call, in the form of RTL. */
if (fndecl)
- /* Get a SYMBOL_REF rtx for the function address. */
- funexp = XEXP (DECL_RTL (fndecl), 0);
+ {
+ /* If this is the first use of the function, see if we need to
+ make an external definition for it. */
+ if (! TREE_USED (fndecl))
+ {
+ assemble_external (fndecl);
+ TREE_USED (fndecl) = 1;
+ }
+
+ /* Get a SYMBOL_REF rtx for the function address. */
+ funexp = XEXP (DECL_RTL (fndecl), 0);
+ }
else
/* Generate an rtx (probably a pseudo-register) for the address. */
{
/* If register arguments require space on the stack and stack space
was not preallocated, allocate stack space here for arguments
passed in registers. */
-#if ! defined(ALLOCATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE)
+#if ! defined(ACCUMULATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE)
if (must_preallocate == 0 && reg_parm_stack_space > 0)
anti_adjust_stack (GEN_INT (reg_parm_stack_space));
#endif
{
if (target == 0)
{
- target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
- copy_to_reg (valreg));
- MEM_IN_STRUCT_P (target)
- = (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
- || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE
- || TREE_CODE (TREE_TYPE (exp)) == QUAL_UNION_TYPE);
+ /* We used leave the value in the location that it is
+ returned in, but that causes problems if it is used more
+ than once in one expression. Rather than trying to track
+ when a copy is required, we always copy when TARGET is
+ not specified. This calling sequence is only used on
+ a few machines and TARGET is usually nonzero. */
+ if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+ {
+ target = assign_stack_temp (BLKmode,
+ int_size_in_bytes (TREE_TYPE (exp)),
+ 0);
+
+ /* Save this temp slot around the pop below. */
+ preserve_temp_slots (target);
+ }
+ else
+ target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
}
- else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
+
+ if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
emit_move_insn (target, gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
copy_to_reg (valreg)));
else
int old_inhibit_defer_pop = inhibit_defer_pop;
int no_queue = 0;
rtx use_insns;
+ /* library calls are never indirect calls. */
+ int current_call_is_indirect = 0;
va_start (p);
orgfun = fun = va_arg (p, rtx);
rtx use_insns;
rtx value;
rtx mem_value = 0;
+ /* library calls are never indirect calls. */
+ int current_call_is_indirect = 0;
va_start (p);
orgfun = fun = va_arg (p, rtx);
/* This isn't already where we want it on the stack, so put it there.
This can either be done with push or copy insns. */
- emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), 0, 0, partial,
- reg, used - size, argblock, ARGS_SIZE_RTX (arg->offset));
+ emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
+ 0, partial, reg, used - size,
+ argblock, ARGS_SIZE_RTX (arg->offset));
}
else
{