You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This file handles the generation of rtl code from tree structure
int current_function_varargs;
+/* Nonzero if current function uses stdarg.h or equivalent.
+ Zero for functions that use varargs.h. */
+
+int current_function_stdarg;
+
/* Quantities of various kinds of registers
used for the current function's args. */
int level;
/* Non-zero if this should survive a call to free_temp_slots. */
int keep;
+ /* The offset of the slot from the frame_pointer, including extra space
+ for alignment. This info is for combine_temp_slots. */
+ int base_offset;
+ /* The size of the slot, including extra space for alignment. This
+ info is for combine_temp_slots. */
+ int full_size;
};
/* List of all temporaries allocated, both available and in use. */
p->pretend_args_size = current_function_pretend_args_size;
p->arg_offset_rtx = current_function_arg_offset_rtx;
p->varargs = current_function_varargs;
+ p->stdarg = current_function_stdarg;
p->uses_const_pool = current_function_uses_const_pool;
p->uses_pic_offset_table = current_function_uses_pic_offset_table;
p->internal_arg_pointer = current_function_internal_arg_pointer;
current_function_pretend_args_size = p->pretend_args_size;
current_function_arg_offset_rtx = p->arg_offset_rtx;
current_function_varargs = p->varargs;
+ current_function_stdarg = p->stdarg;
current_function_uses_const_pool = p->uses_const_pool;
current_function_uses_pic_offset_table = p->uses_pic_offset_table;
current_function_internal_arg_pointer = p->internal_arg_pointer;
p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
p->in_use = p->addr_taken = 0;
p->size = best_p->size - rounded_size;
+ p->base_offset = best_p->base_offset + rounded_size;
+ p->full_size = best_p->full_size - rounded_size;
p->slot = gen_rtx (MEM, BLKmode,
plus_constant (XEXP (best_p->slot, 0),
rounded_size));
stack_slot_list);
best_p->size = rounded_size;
+ best_p->full_size = rounded_size;
}
}
/* The following slot size computation is necessary because we don't
know the actual size of the temporary slot until assign_stack_local
has performed all the frame alignment and size rounding for the
- requested temporary. Otherwise combine_temp_slots won't think that
- adjacent slots really are adjacent. */
+ requested temporary. Note that extra space added for alignment
+ can be either above or below this stack slot depending on which
+ way the frame grows. We include the extra space if and only if it
+ is above this slot. */
#ifdef FRAME_GROWS_DOWNWARD
p->size = frame_offset_old - frame_offset;
#else
- p->size = frame_offset - frame_offset_old;
+ p->size = size;
+#endif
+ /* Now define the fields used by combine_temp_slots. */
+#ifdef FRAME_GROWS_DOWNWARD
+ p->base_offset = frame_offset;
+ p->full_size = frame_offset_old - frame_offset;
+#else
+ p->base_offset = frame_offset_old;
+ p->full_size = frame_offset - frame_offset_old;
#endif
p->address = 0;
p->next = temp_slots;
int delete_q = 0;
if (! q->in_use && GET_MODE (q->slot) == BLKmode)
{
- if (rtx_equal_p (plus_constant (XEXP (p->slot, 0), p->size),
- XEXP (q->slot, 0)))
+ if (p->base_offset + p->full_size == q->base_offset)
{
/* Q comes after P; combine Q into P. */
p->size += q->size;
+ p->full_size += q->full_size;
delete_q = 1;
}
- else if (rtx_equal_p (plus_constant (XEXP (q->slot, 0), q->size),
- XEXP (p->slot, 0)))
+ else if (q->base_offset + q->full_size == p->base_offset)
{
/* P comes after Q; combine P into Q. */
q->size += p->size;
+ q->full_size += p->full_size;
delete_p = 1;
break;
}
We do it so they end up consecutive. */
enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
tree part_type = TREE_TYPE (TREE_TYPE (decl));
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef FRAME_GROWS_DOWNWARD
/* Since part 0 should have a lower address, do it second. */
put_reg_into_stack (function, XEXP (reg, 1),
part_type, part_mode, part_mode);
register rtx entry_parm = 0;
register rtx stack_parm = 0;
CUMULATIVE_ARGS args_so_far;
- enum machine_mode promoted_mode, passed_mode, nominal_mode;
+ enum machine_mode promoted_mode, passed_mode;
+ enum machine_mode nominal_mode, promoted_nominal_mode;
int unsignedp;
/* Total space needed so far for args on the stack,
given as a constant and a tree-expression. */
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
!= void_type_node));
+ current_function_stdarg = stdarg;
+
/* If the reg that the virtual arg pointer will be translated into is
not a fixed reg or is the stack pointer, make a copy of the virtual
arg pointer, and address parms via the copy. The frame pointer is
struct args_size stack_offset;
struct args_size arg_size;
int passed_pointer = 0;
+ int did_conversion = 0;
tree passed_type = DECL_ARG_TYPE (parm);
+ tree nominal_type = TREE_TYPE (parm);
/* Set LAST_NAMED if this is last named arg before some
anonymous args. We treat it as if it were anonymous too. */
/* Find mode of arg as it is passed, and mode of arg
as it should be during execution of this function. */
passed_mode = TYPE_MODE (passed_type);
- nominal_mode = TYPE_MODE (TREE_TYPE (parm));
+ nominal_mode = TYPE_MODE (nominal_type);
/* If the parm's mode is VOID, its value doesn't matter,
and avoid the usual things like emit_move_insn that could crash. */
#endif
)
{
- passed_type = build_pointer_type (passed_type);
+ passed_type = nominal_type = build_pointer_type (passed_type);
passed_pointer = 1;
passed_mode = nominal_mode = Pmode;
}
passed_type, ! last_named);
#endif
- if (entry_parm)
- passed_mode = promoted_mode;
+ if (entry_parm == 0)
+ promoted_mode = passed_mode;
#ifdef SETUP_INCOMING_VARARGS
/* If this is the last named parameter, do any required setup for
Also, indicate when RTL generation is to be suppressed. */
if (last_named && !varargs_setup)
{
- SETUP_INCOMING_VARARGS (args_so_far, passed_mode, passed_type,
+ SETUP_INCOMING_VARARGS (args_so_far, promoted_mode, passed_type,
current_function_pretend_args_size,
second_time);
varargs_setup = 1;
In this case, we call FUNCTION_ARG with NAMED set to 1 instead of
0 as it was the previous time. */
- locate_and_pad_parm (passed_mode, passed_type,
+ locate_and_pad_parm (promoted_mode, passed_type,
#ifdef STACK_PARMS_IN_REG_PARM_AREA
1,
#else
#ifdef FUNCTION_INCOMING_ARG
- FUNCTION_INCOMING_ARG (args_so_far, passed_mode,
+ FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
passed_type,
(! last_named
|| varargs_setup)) != 0,
#else
- FUNCTION_ARG (args_so_far, passed_mode,
+ FUNCTION_ARG (args_so_far, promoted_mode,
passed_type,
! last_named || varargs_setup) != 0,
#endif
rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
if (offset_rtx == const0_rtx)
- stack_parm = gen_rtx (MEM, passed_mode, internal_arg_pointer);
+ stack_parm = gen_rtx (MEM, promoted_mode, internal_arg_pointer);
else
- stack_parm = gen_rtx (MEM, passed_mode,
+ stack_parm = gen_rtx (MEM, promoted_mode,
gen_rtx (PLUS, Pmode,
internal_arg_pointer, offset_rtx));
/* If this parameter was passed both in registers and in the stack,
use the copy on the stack. */
- if (MUST_PASS_IN_STACK (passed_mode, passed_type))
+ if (MUST_PASS_IN_STACK (promoted_mode, passed_type))
entry_parm = 0;
#ifdef FUNCTION_ARG_PARTIAL_NREGS
if (entry_parm)
{
- int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, passed_mode,
+ int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
passed_type, ! last_named);
if (nregs > 0)
??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell
whether this parameter already has a stack slot allocated,
because an arg block exists only if current_function_args_size
- is larger than some threshhold, and we haven't calculated that
+ is larger than some threshold, and we haven't calculated that
yet. So, for now, we just assume that stack slots never exist
in this case. */
|| REG_PARM_STACK_SPACE (fndecl) > 0
/* Update info on where next arg arrives in registers. */
- FUNCTION_ARG_ADVANCE (args_so_far, passed_mode,
+ FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
passed_type, ! last_named);
/* If this is our second time through, we are done with this parm. */
We'll make another stack slot, if we need one. */
{
int thisparm_boundary
- = FUNCTION_ARG_BOUNDARY (passed_mode, passed_type);
+ = FUNCTION_ARG_BOUNDARY (promoted_mode, passed_type);
if (GET_MODE_ALIGNMENT (nominal_mode) > thisparm_boundary)
stack_parm = 0;
/* If a BLKmode arrives in registers, copy it to a stack slot. */
if (GET_CODE (entry_parm) == REG)
{
- int size_stored = CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
- UNITS_PER_WORD);
+ int size_stored
+ = CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
+ UNITS_PER_WORD);
/* Note that we will be storing an integral number of words.
So we have to be careful to ensure that we allocate an
if (stack_parm == 0)
{
stack_parm
- = assign_stack_local (GET_MODE (entry_parm), size_stored, 0);
- /* If this is a memory ref that contains aggregate components,
- mark it as such for cse and loop optimize. */
+ = assign_stack_local (GET_MODE (entry_parm),
+ size_stored, 0);
+
+ /* If this is a memory ref that contains aggregate
+ components, mark it as such for cse and loop optimize. */
MEM_IN_STRUCT_P (stack_parm) = aggregate;
}
unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
-#ifdef PROMOTE_FUNCTION_ARGS
- nominal_mode = promote_mode (TREE_TYPE (parm), nominal_mode,
- &unsignedp, 1);
-#endif
+ promoted_nominal_mode
+ = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
- parmreg = gen_reg_rtx (nominal_mode);
+ parmreg = gen_reg_rtx (promoted_nominal_mode);
REG_USERVAR_P (parmreg) = 1;
/* If this was an item that we received a pointer to, set DECL_RTL
appropriately. */
if (passed_pointer)
{
- DECL_RTL (parm) = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
+ DECL_RTL (parm)
+ = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
MEM_IN_STRUCT_P (DECL_RTL (parm)) = aggregate;
}
else
DECL_RTL (parm) = parmreg;
/* Copy the value into the register. */
- if (GET_MODE (parmreg) != GET_MODE (entry_parm))
+ if (nominal_mode != passed_mode
+ || promoted_nominal_mode != promoted_mode)
{
- /* If ENTRY_PARM is a hard register, it might be in a register
+ /* ENTRY_PARM has been converted to PROMOTED_MODE, its
+ mode, by the caller. We now have to convert it to
+ NOMINAL_MODE, if different. However, PARMREG may be in
+ a diffent mode than NOMINAL_MODE if it is being stored
+ promoted.
+
+ If ENTRY_PARM is a hard register, it might be in a register
not valid for operating in its mode (e.g., an odd-numbered
register for a DFmode). In that case, moves are the only
thing valid, so we can't do a convert from there. This
emit_move_insn (tempreg, validize_mem (entry_parm));
push_to_sequence (conversion_insns);
- convert_move (parmreg, tempreg, unsignedp);
+ tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
+
+ expand_assignment (parm,
+ make_tree (nominal_type, tempreg), 0, 0);
conversion_insns = get_insns ();
+ did_conversion = 1;
end_sequence ();
}
else
&& FUNCTION_ARG_CALLEE_COPIES (args_so_far,
TYPE_MODE (DECL_ARG_TYPE (parm)),
DECL_ARG_TYPE (parm),
- ! last_named))
+ ! last_named)
+ && ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
{
rtx copy;
tree type = DECL_ARG_TYPE (parm);
store_expr (parm, copy, 0);
emit_move_insn (parmreg, XEXP (copy, 0));
conversion_insns = get_insns ();
+ did_conversion = 1;
end_sequence ();
}
#endif /* FUNCTION_ARG_CALLEE_COPIES */
an invalid address, such memory-equivalences
as we make here would screw up life analysis for it. */
if (nominal_mode == passed_mode
- && ! conversion_insns
+ && ! did_conversion
&& GET_CODE (entry_parm) == MEM
&& entry_parm == stack_parm
&& stack_offset.var == 0
/* Value must be stored in the stack slot STACK_PARM
during function execution. */
- if (passed_mode != nominal_mode)
+ if (promoted_mode != nominal_mode)
{
/* Conversion is required. */
rtx tempreg = gen_reg_rtx (GET_MODE (entry_parm));
entry_parm = convert_to_mode (nominal_mode, tempreg,
TREE_UNSIGNED (TREE_TYPE (parm)));
conversion_insns = get_insns ();
+ did_conversion = 1;
end_sequence ();
}
MEM_IN_STRUCT_P (stack_parm) = aggregate;
}
- if (passed_mode != nominal_mode)
+ if (promoted_mode != nominal_mode)
{
push_to_sequence (conversion_insns);
emit_move_insn (validize_mem (stack_parm),
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
arg = TREE_CHAIN (arg))
if (GET_CODE (DECL_INCOMING_RTL (arg)) == REG
- && REGNO (DECL_INCOMING_RTL (arg)) == regno)
+ && REGNO (DECL_INCOMING_RTL (arg)) == regno
+ && TYPE_MODE (DECL_ARG_TYPE (arg)) == TYPE_MODE (TREE_TYPE (arg)))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
int unsignedp = TREE_UNSIGNED (TREE_TYPE (arg));
but for arguments instead of local variables. */
void
-setjmp_args_warning (block)
- tree block;
+setjmp_args_warning ()
{
register tree decl;
for (decl = DECL_ARGUMENTS (current_function_decl);
current_function_outgoing_args_size = 0;
- /* Initialize the insn lengths. */
- init_insn_lengths ();
-
/* Prevent ever trying to delete the first instruction of a function.
Also tell final how to output a linenum before the function prologue. */
emit_line_note (filename, line);
/* Indicate we have no need of a frame pointer yet. */
frame_pointer_needed = 0;
- /* By default assume not varargs. */
+ /* By default assume not varargs or stdarg. */
current_function_varargs = 0;
+ current_function_stdarg = 0;
}
/* Indicate that the current function uses extra args