Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#include "config.h"
#include "flags.h"
#include "function.h"
#include "expr.h"
+#include "optabs.h"
#include "hard-reg-set.h"
#include "insn-config.h"
+#include "ggc.h"
#include "recog.h"
-#if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
-#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
-#endif
-
static rtx break_out_memory_refs PARAMS ((rtx));
static void emit_stack_probe PARAMS ((rtx));
rtx
plus_constant_wide (x, c)
- register rtx x;
- register HOST_WIDE_INT c;
+ rtx x;
+ HOST_WIDE_INT c;
{
- register RTX_CODE code;
+ RTX_CODE code;
rtx y;
- register enum machine_mode mode;
- register rtx tem;
+ enum machine_mode mode;
+ rtx tem;
int all_constant = 0;
if (c == 0)
rtx x;
rtx *constptr;
{
- register rtx x0, x1;
+ rtx x0, x1;
rtx tem;
if (GET_CODE (x) != PLUS)
static rtx
break_out_memory_refs (x)
- register rtx x;
+ rtx x;
{
if (GET_CODE (x) == MEM
|| (CONSTANT_P (x) && CONSTANT_ADDRESS_P (x)
else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
|| GET_CODE (x) == MULT)
{
- register rtx op0 = break_out_memory_refs (XEXP (x, 0));
- register rtx op1 = break_out_memory_refs (XEXP (x, 1));
+ rtx op0 = break_out_memory_refs (XEXP (x, 0));
+ rtx op1 = break_out_memory_refs (XEXP (x, 1));
if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
x = gen_rtx_fmt_ee (GET_CODE (x), Pmode, op0, op1);
case SUBREG:
if (POINTERS_EXTEND_UNSIGNED >= 0
+ && (SUBREG_PROMOTED_VAR_P (x) || REG_POINTER (SUBREG_REG (x)))
&& GET_MODE (SUBREG_REG (x)) == to_mode)
return SUBREG_REG (x);
break;
rtx
copy_all_regs (x)
- register rtx x;
+ rtx x;
{
if (GET_CODE (x) == REG)
{
else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
|| GET_CODE (x) == MULT)
{
- register rtx op0 = copy_all_regs (XEXP (x, 0));
- register rtx op1 = copy_all_regs (XEXP (x, 1));
+ rtx op0 = copy_all_regs (XEXP (x, 0));
+ rtx op1 = copy_all_regs (XEXP (x, 1));
if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
x = gen_rtx_fmt_ee (GET_CODE (x), Pmode, op0, op1);
}
rtx
memory_address (mode, x)
enum machine_mode mode;
- register rtx x;
+ rtx x;
{
- register rtx oldx = x;
+ rtx oldx = x;
if (GET_CODE (x) == ADDRESSOF)
return x;
#ifdef POINTERS_EXTEND_UNSIGNED
- if (GET_MODE (x) == ptr_mode)
+ if (GET_MODE (x) != Pmode)
x = convert_memory_address (Pmode, x);
#endif
|| TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
RTX_UNCHANGING_P (ref) = 1;
}
-
-/* Given REF, a MEM, and T, either the type of X or the expression
- corresponding to REF, set the memory attributes. OBJECTP is nonzero
- if we are making a new object of this type. */
-
-void
-set_mem_attributes (ref, t, objectp)
- rtx ref;
- tree t;
- int objectp;
-{
- tree type;
-
- /* It can happen that type_for_mode was given a mode for which there
- is no language-level type. In which case it returns NULL, which
- we can see here. */
- if (t == NULL_TREE)
- return;
-
- type = TYPE_P (t) ? t : TREE_TYPE (t);
-
- /* Get the alias set from the expression or type (perhaps using a
- front-end routine) and then copy bits from the type. */
-
- /* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY (type)
- here, because, in C and C++, the fact that a location is accessed
- through a const expression does not mean that the value there can
- never change. */
- set_mem_alias_set (ref, get_alias_set (t));
- MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);
- MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
-
- /* If we are making an object of this type, we know that it is a scalar if
- the type is not an aggregate. */
- if (objectp && ! AGGREGATE_TYPE_P (type))
- MEM_SCALAR_P (ref) = 1;
-
- /* If T is a type, this is all we can do. Otherwise, we may be able
- to deduce some more information about the expression. */
- if (TYPE_P (t))
- return;
-
- maybe_set_unchanging (ref, t);
- if (TREE_THIS_VOLATILE (t))
- MEM_VOLATILE_P (ref) = 1;
-
- /* Now see if we can say more about whether it's an aggregate or
- scalar. If we already know it's an aggregate, don't bother. */
- if (MEM_IN_STRUCT_P (ref))
- return;
-
- /* Now remove any NOPs: they don't change what the underlying object is.
- Likewise for SAVE_EXPR. */
- while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
- || TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR)
- t = TREE_OPERAND (t, 0);
-
- /* Since we already know the type isn't an aggregate, if this is a decl,
- it must be a scalar. Or if it is a reference into an aggregate,
- this is part of an aggregate. Otherwise we don't know. */
- if (DECL_P (t))
- MEM_SCALAR_P (ref) = 1;
- else if (TREE_CODE (t) == COMPONENT_REF || TREE_CODE (t) == ARRAY_REF
- || TREE_CODE (t) == ARRAY_RANGE_REF
- || TREE_CODE (t) == BIT_FIELD_REF)
- MEM_IN_STRUCT_P (ref) = 1;
-}
\f
/* Return a modified copy of X with its memory address copied
into a temporary register to protect it from side effects.
copy_to_reg (x)
rtx x;
{
- register rtx temp = gen_reg_rtx (GET_MODE (x));
+ rtx temp = gen_reg_rtx (GET_MODE (x));
/* If not an operand, must be an address with PLUS and MULT so
do the computation. */
enum machine_mode mode;
rtx x;
{
- register rtx temp = gen_reg_rtx (mode);
+ rtx temp = gen_reg_rtx (mode);
/* If not an operand, must be an address with PLUS and MULT so
do the computation. */
enum machine_mode mode;
rtx x;
{
- register rtx temp, insn, set;
+ rtx temp, insn, set;
if (GET_CODE (x) == REG)
return x;
if (CONSTANT_P (x)
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == temp)
- {
- rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-
- if (note)
- XEXP (note, 0) = x;
- else
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, x, REG_NOTES (insn));
- }
+ set_unique_reg_note (insn, REG_EQUAL, x);
return temp;
}
force_not_mem (x)
rtx x;
{
- register rtx temp;
+ rtx temp;
if (GET_CODE (x) != MEM || GET_MODE (x) == BLKmode)
return x;
rtx x, target;
enum machine_mode mode;
{
- register rtx temp;
+ rtx temp;
if (target && GET_CODE (target) == REG)
temp = target;
round_push (size)
rtx size;
{
-#ifdef PREFERRED_STACK_BOUNDARY
int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
if (align == 1)
return size;
NULL_RTX, 1);
size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1);
}
-#endif /* PREFERRED_STACK_BOUNDARY */
return size;
}
\f
/* 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
If we have to align, we must leave space in SIZE for the hole
that might result from the alignment operation. */
-#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || ! defined (PREFERRED_STACK_BOUNDARY)
+#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET)
#define MUST_ALIGN 1
#else
#define MUST_ALIGN (PREFERRED_STACK_BOUNDARY < BIGGEST_ALIGNMENT)
/* See optimize_save_area_alloca to understand what is being
set up here. */
-#if !defined(PREFERRED_STACK_BOUNDARY) || !defined(MUST_ALIGN) || (PREFERRED_STACK_BOUNDARY != BIGGEST_ALIGNMENT)
- /* If anyone creates a target with these characteristics, let them
- know that our optimization cannot work correctly in such a case. */
- abort ();
-#endif
+ /* ??? Code below assumes that the save area needs maximal
+ alignment. This constraint may be too strong. */
+ if (PREFERRED_STACK_BOUNDARY != BIGGEST_ALIGNMENT)
+ abort ();
if (GET_CODE (size) == CONST_INT)
{
way of knowing which systems have this problem. So we avoid even
momentarily mis-aligning the stack. */
-#ifdef PREFERRED_STACK_BOUNDARY
/* If we added a variable amount to SIZE,
we can no longer assume it is aligned. */
#if !defined (SETJMP_VIA_SAVE_AREA)
if (MUST_ALIGN || known_align % PREFERRED_STACK_BOUNDARY != 0)
#endif
size = round_push (size);
-#endif
do_pending_stack_adjust ();
/* We ought to be called always on the toplevel and stack ought to be aligned
- propertly. */
-#ifdef PREFERRED_STACK_BOUNDARY
+ properly. */
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. */
enum machine_mode mode = STACK_SIZE_MODE;
insn_operand_predicate_fn pred;
- 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
-
+ /* We don't have to check against the predicate for operand 0 since
+ TARGET is known to be a pseudo of the proper mode, which must
+ be valid for the operand. For operand 1, convert to the
+ proper mode and validate. */
if (mode == VOIDmode)
- mode = Pmode;
+ mode = insn_data[(int) CODE_FOR_allocate_stack].operand[1].mode;
pred = insn_data[(int) CODE_FOR_allocate_stack].operand[1].predicate;
if (pred && ! ((*pred) (size, mode)))
NULL_RTX, 1, OPTAB_WIDEN);
#endif
emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
- 0, space_available);
+ space_available);
#ifdef HAVE_trap
if (HAVE_trap)
emit_insn (gen_trap ());
rtx libfunc;
{
stack_check_libfunc = libfunc;
+ ggc_add_rtx_root (&stack_check_libfunc, 1);
}
\f
/* Emit one stack probe at ADDRESS, an address within the stack. */
HOST_WIDE_INT first;
rtx size;
{
- /* First see if the front end has set up a function for us to call to
+ /* First ensure SIZE is Pmode. */
+ if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
+ size = convert_to_mode (Pmode, size, 1);
+
+ /* Next see if the front end has set up a function for us to call to
check the stack. */
if (stack_check_libfunc != 0)
{
addr = convert_memory_address (ptr_mode, addr);
#endif
- emit_library_call (stack_check_libfunc, 0, VOIDmode, 1, addr,
+ emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr,
ptr_mode);
}
emit_label (test_lab);
emit_cmp_and_jump_insns (test_addr, last_addr, CMP_OPCODE,
- NULL_RTX, Pmode, 1, 0, loop_lab);
+ NULL_RTX, Pmode, 1, loop_lab);
emit_jump (end_lab);
emit_note (NULL, NOTE_INSN_LOOP_END);
emit_label (end_lab);
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. */
+ and 0 otherwise. */
rtx
hard_function_value (valtype, func, outgoing)