/* Subroutines for manipulating rtx's in semantically interesting ways.
- Copyright (C) 1987, 91, 94-97, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "toplev.h"
#include "rtl.h"
#include "tree.h"
+#include "tm_p.h"
#include "flags.h"
+#include "function.h"
#include "expr.h"
#include "hard-reg-set.h"
#include "insn-config.h"
#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
#endif
-static rtx break_out_memory_refs PROTO((rtx));
-static void emit_stack_probe PROTO((rtx));
+static rtx break_out_memory_refs PARAMS ((rtx));
+static void emit_stack_probe PARAMS ((rtx));
/* Truncate and perhaps sign-extend C as appropriate for MODE. */
if (GET_CODE (x) == LO_SUM)
return gen_rtx_LO_SUM (mode, XEXP (x, 0),
- plus_constant_for_output (XEXP (x, 1), c));
+ plus_constant_for_output (XEXP (x, 1), c));
else
return plus_constant (x, c);
if (oldx == x)
return x;
else if (GET_CODE (x) == REG)
- mark_reg_pointer (x, 1);
+ mark_reg_pointer (x, BITS_PER_UNIT);
else if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
- mark_reg_pointer (XEXP (x, 0), 1);
+ mark_reg_pointer (XEXP (x, 0), BITS_PER_UNIT);
/* OLDX may have been the address on a temporary. Update the address
to indicate that X is now used. */
if (GET_CODE (x) == REG)
return x;
+
temp = gen_reg_rtx (mode);
+
+ if (! general_operand (x, mode))
+ x = force_operand (x, NULL_RTX);
+
insn = emit_move_insn (temp, x);
/* Let optimizers know that TEMP's value never changes
if (adjust == const0_rtx)
return;
+ /* We expect all variable sized adjustments to be multiple of
+ PREFERRED_STACK_BOUNDARY. */
+ if (GET_CODE (adjust) == CONST_INT)
+ stack_pointer_delta -= INTVAL (adjust);
+
temp = expand_binop (Pmode,
#ifdef STACK_GROWS_DOWNWARD
add_optab,
if (adjust == const0_rtx)
return;
+ /* We expect all variable sized adjustments to be multiple of
+ PREFERRED_STACK_BOUNDARY. */
+ if (GET_CODE (adjust) == CONST_INT)
+ stack_pointer_delta += INTVAL (adjust);
+
temp = expand_binop (Pmode,
#ifdef STACK_GROWS_DOWNWARD
sub_optab,
{
rtx sa = *psave;
/* The default is that we use a move insn and save in a Pmode object. */
- rtx (*fcn) PROTO ((rtx, rtx)) = gen_move_insn;
+ rtx (*fcn) PARAMS ((rtx, rtx)) = gen_move_insn;
enum machine_mode mode = STACK_SAVEAREA_MODE (save_level);
/* See if this machine has anything special to do for this kind of save. */
rtx sa;
{
/* The default is that we use a move insn. */
- rtx (*fcn) PROTO ((rtx, rtx)) = gen_move_insn;
+ rtx (*fcn) PARAMS ((rtx, rtx)) = gen_move_insn;
/* See if this machine has anything special to do for this kind of save. */
switch (save_level)
if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
size = convert_to_mode (Pmode, size, 1);
+ /* We can't attempt to minimize alignment necessary, because we don't
+ know the final value of preferred_stack_boundary yet while executing
+ this code. */
+#ifdef PREFERRED_STACK_BOUNDARY
+ cfun->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+#endif
+
/* We will need to ensure that the address we return is aligned to
BIGGEST_ALIGNMENT. If STACK_DYNAMIC_OFFSET is defined, we don't
always know its final value at this point in the compilation (it
do_pending_stack_adjust ();
+ /* We ought to be called always on the toplevel and stack ought to be aligned
+ propertly. */
+#ifdef PREFERRED_STACK_BOUNDARY
+ if (stack_pointer_delta % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT))
+ abort ();
+#endif
+
/* If needed, check that we have the required amount of stack. Take into
account what has already been checked. */
if (flag_stack_check && ! STACK_CHECK_BUILTIN)
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (Pmode);
- mark_reg_pointer (target, known_align / BITS_PER_UNIT);
+ mark_reg_pointer (target, known_align);
/* Perform the required allocation from the stack. Some systems do
this differently than simply incrementing/decrementing from the
if (HAVE_allocate_stack)
{
enum machine_mode mode = STACK_SIZE_MODE;
+ insn_operand_predicate_fn pred;
- if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][0]
- && ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][0])
- (target, Pmode)))
+ pred = insn_data[(int) CODE_FOR_allocate_stack].operand[0].predicate;
+ if (pred && ! ((*pred) (target, Pmode)))
#ifdef POINTERS_EXTEND_UNSIGNED
target = convert_memory_address (Pmode, target);
#else
target = copy_to_mode_reg (Pmode, target);
#endif
+
+ if (mode == VOIDmode)
+ mode = Pmode;
+
size = convert_modes (mode, ptr_mode, size, 1);
- if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][1]
- && ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][1])
- (size, mode)))
+ pred = insn_data[(int) CODE_FOR_allocate_stack].operand[1].predicate;
+ if (pred && ! ((*pred) (size, mode)))
size = copy_to_mode_reg (mode, size);
emit_insn (gen_allocate_stack (target, size));
emit_move_insn (target, virtual_stack_dynamic_rtx);
#endif
size = convert_modes (Pmode, ptr_mode, size, 1);
+
+ /* Check stack bounds if necessary. */
+ if (current_function_limit_stack)
+ {
+ rtx available;
+ rtx space_available = gen_label_rtx ();
+#ifdef STACK_GROWS_DOWNWARD
+ available = expand_binop (Pmode, sub_optab,
+ stack_pointer_rtx, stack_limit_rtx,
+ NULL_RTX, 1, OPTAB_WIDEN);
+#else
+ available = expand_binop (Pmode, sub_optab,
+ stack_limit_rtx, stack_pointer_rtx,
+ NULL_RTX, 1, OPTAB_WIDEN);
+#endif
+ emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
+ 0, space_available);
+#ifdef HAVE_trap
+ if (HAVE_trap)
+ emit_insn (gen_trap ());
+ else
+#endif
+ error ("stack limits not supported on this target");
+ emit_barrier ();
+ emit_label (space_available);
+ }
+
anti_adjust_stack (size);
#ifdef SETJMP_VIA_SAVE_AREA
if (setjmpless_size != NULL_RTX)
return target;
}
\f
+/* A front end may want to override GCC's stack checking by providing a
+ run-time routine to call to check the stack, so provide a mechanism for
+ calling that routine. */
+
+static rtx stack_check_libfunc;
+
+void
+set_stack_check_libfunc (libfunc)
+ rtx libfunc;
+{
+ stack_check_libfunc = libfunc;
+}
+\f
/* Emit one stack probe at ADDRESS, an address within the stack. */
static void
HOST_WIDE_INT first;
rtx size;
{
- /* First see if we have an insn to check the stack. Use it if so. */
+ /* First see if the front end has set up a function for us to call to
+ check the stack. */
+ if (stack_check_libfunc != 0)
+ emit_library_call (stack_check_libfunc, 0, VOIDmode, 1,
+ memory_address (QImode,
+ gen_rtx (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ plus_constant (size, first))),
+ ptr_mode);
+
+ /* Next see if we have an insn to check the stack. Use it if so. */
#ifdef HAVE_check_stack
- if (HAVE_check_stack)
+ else if (HAVE_check_stack)
{
+ insn_operand_predicate_fn pred;
rtx last_addr
= force_operand (gen_rtx_STACK_GROW_OP (Pmode,
stack_pointer_rtx,
plus_constant (size, first)),
NULL_RTX);
- if (insn_operand_predicate[(int) CODE_FOR_check_stack][0]
- && ! ((*insn_operand_predicate[(int) CODE_FOR_check_stack][0])
- (last_address, Pmode)))
- last_address = copy_to_mode_reg (Pmode, last_address);
+ pred = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate;
+ if (pred && ! ((*pred) (last_addr, Pmode)))
+ last_addr = copy_to_mode_reg (Pmode, last_addr);
- emit_insn (gen_check_stack (last_address));
- return;
+ emit_insn (gen_check_stack (last_addr));
}
#endif
/* If we have to generate explicit probes, see if we have a constant
small number of them to generate. If so, that's the easy case. */
- if (GET_CODE (size) == CONST_INT
- && INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL)
+ else if (GET_CODE (size) == CONST_INT
+ && INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL)
{
HOST_WIDE_INT offset;
emit_note (NULL_PTR, NOTE_INSN_LOOP_END);
emit_label (end_lab);
- /* If will be doing stupid optimization, show test_addr is still live. */
- if (obey_regdecls)
- emit_insn (gen_rtx_USE (VOIDmode, test_addr));
-
emit_stack_probe (last_addr);
}
}
in which a scalar value of data type VALTYPE
was returned by a function call to function FUNC.
FUNC is a FUNCTION_DECL node if the precise function is known,
- otherwise 0. */
+ otherwise 0.
+ OUTGOING is 1 if on a machine with register windows this function
+ should return the register in which the function will put its result
+ and 0 otherwise. */
rtx
-hard_function_value (valtype, func)
+hard_function_value (valtype, func, outgoing)
tree valtype;
tree func ATTRIBUTE_UNUSED;
+ int outgoing ATTRIBUTE_UNUSED;
{
- rtx val = FUNCTION_VALUE (valtype, func);
+ rtx val;
+
+#ifdef FUNCTION_OUTGOING_VALUE
+ if (outgoing)
+ val = FUNCTION_OUTGOING_VALUE (valtype, func);
+ else
+#endif
+ val = FUNCTION_VALUE (valtype, func);
+
if (GET_CODE (val) == REG
&& GET_MODE (val) == BLKmode)
{
- int bytes = int_size_in_bytes (valtype);
+ unsigned HOST_WIDE_INT bytes = int_size_in_bytes (valtype);
enum machine_mode tmpmode;
+
for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
- tmpmode != MAX_MACHINE_MODE;
+ tmpmode != VOIDmode;
tmpmode = GET_MODE_WIDER_MODE (tmpmode))
{
/* Have we found a large enough mode? */
}
/* No suitable mode found. */
- if (tmpmode == MAX_MACHINE_MODE)
+ if (tmpmode == VOIDmode)
abort ();
PUT_MODE (val, tmpmode);