/* Analyze RTL for C-Compiler
- Copyright (C) 1987-1991 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 9-5, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
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. */
#include "config.h"
if (code == REG)
return ! (REGNO (x) == FRAME_POINTER_REGNUM
+ || REGNO (x) == HARD_FRAME_POINTER_REGNUM
|| REGNO (x) == ARG_POINTER_REGNUM
|| RTX_UNCHANGING_P (x));
and arg pointers and not just the register number in case we have
eliminated the frame and/or arg pointer and are using it
for pseudos. */
- return ! (x == frame_pointer_rtx || x == arg_pointer_rtx);
+ return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+ || x == arg_pointer_rtx);
case LO_SUM:
/* The operand 0 of a LO_SUM is considered constant
case REG:
/* As in rtx_varies_p, we have to use the actual rtx, not reg number. */
- return ! (x == frame_pointer_rtx || x == stack_pointer_rtx
- || x == arg_pointer_rtx);
+ return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+ || x == stack_pointer_rtx || x == arg_pointer_rtx);
case CONST:
return rtx_addr_can_trap_p (XEXP (x, 0));
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
- if (rtx_addr_varies_p (XEXP (x, i)))
- return 1;
+ {
+ if (rtx_addr_varies_p (XEXP (x, i)))
+ return 1;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (rtx_addr_varies_p (XVECEXP (x, i, j)))
+ return 1;
+ }
return 0;
}
\f
Only obvious integer terms are detected.
This is used in cse.c with the `related_value' field.*/
-int
+HOST_WIDE_INT
get_integer_term (x)
rtx x;
{
for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+ && (reg_overlap_mentioned_p (reg, PATTERN (insn))
+ || (GET_CODE (insn) == CALL_INSN
+ && (find_reg_fusage (insn, USE, reg)
+ || find_reg_fusage (insn, CLOBBER, reg)))))
return 1;
return 0;
}
case TRAP_IF:
return reg_overlap_mentioned_p (x, TRAP_CONDITION (body));
+ case UNSPEC:
+ case UNSPEC_VOLATILE:
case PARALLEL:
for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
if (reg_referenced_p (x, XVECEXP (body, 0, i)))
/* Nonzero if register REG is referenced in an insn between
FROM_INSN and TO_INSN (exclusive of those two). Sets of REG do
- not count. */
+ not count. */
int
reg_referenced_between_p (reg, from_insn, to_insn)
for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- && reg_referenced_p (reg, PATTERN (insn)))
+ && (reg_referenced_p (reg, PATTERN (insn))
+ || (GET_CODE (insn) == CALL_INSN
+ && find_reg_fusage (insn, USE, reg))))
return 1;
return 0;
}
for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- && reg_set_p (reg, PATTERN (insn)))
+ && reg_set_p (reg, insn))
return 1;
return 0;
}
static rtx reg_set_reg;
static int reg_set_flag;
-void
-reg_set_p_1 (x)
+static void
+reg_set_p_1 (x, pat)
rtx x;
{
/* We don't want to return 1 if X is a MEM that contains a register
|| (GET_CODE (insn) == CALL_INSN
/* We'd like to test call_used_regs here, but rtlanal.c can't
reference that variable due to its use in genattrtab. So
- we'll just be more conservative. */
+ we'll just be more conservative.
+
+ ??? Unless we could ensure that the CALL_INSN_FUNCTION_USAGE
+ information holds all clobbered registers. */
&& ((GET_CODE (reg) == REG
&& REGNO (reg) < FIRST_PSEUDO_REGISTER)
- || GET_CODE (reg) == MEM)))
+ || GET_CODE (reg) == MEM
+ || find_reg_fusage (insn, CLOBBER, reg))))
return 1;
body = PATTERN (insn);
{
enum rtx_code code = GET_CODE (x);
char *fmt;
- int i;
+ int i, j;
switch (code)
{
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e'
- && modified_between_p (XEXP (x, i), start, end))
+ {
+ if (fmt[i] == 'e' && modified_between_p (XEXP (x, i), start, end))
+ return 1;
+
+ if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (modified_between_p (XVECEXP (x, i, j), start, end))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Similar to reg_set_p, but check all registers in X. Return 0 only if none
+ of them are modified in INSN. Return 1 if X contains a MEM; this routine
+ does not perform any memory aliasing. */
+
+int
+modified_in_p (x, insn)
+ rtx x;
+ rtx insn;
+{
+ enum rtx_code code = GET_CODE (x);
+ char *fmt;
+ int i, j;
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return 0;
+
+ case PC:
+ case CC0:
return 1;
+ case MEM:
+ /* If the memory is not constant, assume it is modified. If it is
+ constant, we still have to check the address. */
+ if (! RTX_UNCHANGING_P (x))
+ return 1;
+ break;
+
+ case REG:
+ return reg_set_p (x, insn);
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e' && modified_in_p (XEXP (x, i), insn))
+ return 1;
+
+ if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (modified_in_p (XVECEXP (x, i, j), insn))
+ return 1;
+ }
+
return 0;
}
\f
{
for (i = 0, set = 0; i < XVECLEN (PATTERN (insn), 0); i++)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
- && ! (find_reg_note (insn, REG_UNUSED,
- SET_DEST (XVECEXP (PATTERN (insn), 0, i)))
- || side_effects_p (XVECEXP (PATTERN (insn), 0, i))))
+ && (! find_reg_note (insn, REG_UNUSED,
+ SET_DEST (XVECEXP (PATTERN (insn), 0, i)))
+ || side_effects_p (XVECEXP (PATTERN (insn), 0, i))))
{
if (set)
return 0;
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
{
rtx set = single_set (p);
- rtx note = find_reg_note (p, REG_EQUAL, 0);
+ rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX);
if (set && rtx_equal_p (x, SET_DEST (set)))
{
{
case REG:
i = REGNO (x);
+
+ /* If we modifying the stack, frame, or argument pointer, it will
+ clobber a virtual register. In fact, we could be more precise,
+ but it isn't worth it. */
+ if ((i == STACK_POINTER_REGNUM
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ || i == ARG_POINTER_REGNUM
+#endif
+ || i == FRAME_POINTER_REGNUM)
+ && regno >= FIRST_VIRTUAL_REGISTER && regno <= LAST_VIRTUAL_REGISTER)
+ return 1;
+
return (endregno > i
&& regno < i + (i < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (i, GET_MODE (x))
endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
- return refers_to_regno_p (regno, endregno, in, 0);
+ return refers_to_regno_p (regno, endregno, in, NULL_PTR);
}
\f
/* Used for communications between the next few functions. */
/* Return the last value to which REG was set prior to INSN. If we can't
find it easily, return 0.
- We only return a REG or constant because it is too hard to check if a
- MEM remains unchanged. */
+ We only return a REG, SUBREG, or constant because it is too hard to
+ check if a MEM remains unchanged. */
rtx
reg_set_last (x, insn)
If we find a set of X, ensure that its SET_SRC remains unchanged. */
+ /* We compare with <= here, because reg_set_last_last_regno
+ is actually the number of the first reg *not* in X. */
for (;
insn && GET_CODE (insn) != CODE_LABEL
&& ! (GET_CODE (insn) == CALL_INSN
else if (reg_set_last_value)
{
if (CONSTANT_P (reg_set_last_value)
- || (GET_CODE (reg_set_last_value) == REG
+ || ((GET_CODE (reg_set_last_value) == REG
+ || GET_CODE (reg_set_last_value) == SUBREG)
&& ! reg_set_between_p (reg_set_last_value,
- NEXT_INSN (insn), orig_insn)))
+ insn, orig_insn)))
return reg_set_last_value;
else
return 0;
return 0;
}
\f
-/* This is 1 until after reload pass. */
+/* This is 1 until after the rtl generation pass. */
int rtx_equal_function_value_matters;
/* Return 1 if X and Y are identical-looking rtx's.
{
switch (fmt[i])
{
+ case 'w':
+ if (XWINT (x, i) != XWINT (y, i))
+ return 0;
+ break;
+
case 'n':
case 'i':
if (XINT (x, i) != XINT (y, i))
return 1;
}
+ if (GET_CODE (insn) == CALL_INSN
+ && find_regno_fusage (insn, CLOBBER, test_regno))
+ return 1;
+
if (GET_CODE (PATTERN (insn)) == SET)
{
rtx dest = SET_DEST (PATTERN (insn));
}
/* Return the reg-note of kind KIND in insn INSN which applies to register
- number REGNO, if any. Return 0 if there is no such reg-note. */
+ number REGNO, if any. Return 0 if there is no such reg-note. Note that
+ the REGNO of this NOTE need not be REGNO if REGNO is a hard register;
+ it might be the case that the note overlaps REGNO. */
rtx
find_regno_note (insn, kind, regno)
/* Verify that it is a register, so that scratch and MEM won't cause a
problem here. */
&& GET_CODE (XEXP (link, 0)) == REG
- && REGNO (XEXP (link, 0)) == regno)
+ && REGNO (XEXP (link, 0)) <= regno
+ && ((REGNO (XEXP (link, 0))
+ + (REGNO (XEXP (link, 0)) >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (REGNO (XEXP (link, 0)),
+ GET_MODE (XEXP (link, 0)))))
+ > regno))
return link;
return 0;
}
+
+/* Return true if DATUM, or any overlap of DATUM, of kind CODE is found
+ in the CALL_INSN_FUNCTION_USAGE information of INSN. */
+
+int
+find_reg_fusage (insn, code, datum)
+ rtx insn;
+ enum rtx_code code;
+ rtx datum;
+{
+ /* If it's not a CALL_INSN, it can't possibly have a
+ CALL_INSN_FUNCTION_USAGE field, so don't bother checking. */
+ if (GET_CODE (insn) != CALL_INSN)
+ return 0;
+
+ if (! datum)
+ abort();
+
+ if (GET_CODE (datum) != REG)
+ {
+ register rtx link;
+
+ for (link = CALL_INSN_FUNCTION_USAGE (insn);
+ link;
+ link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == code
+ && rtx_equal_p (datum, SET_DEST (XEXP (link, 0))))
+ return 1;
+ }
+ else
+ {
+ register int regno = REGNO (datum);
+
+ /* CALL_INSN_FUNCTION_USAGE information cannot contain references
+ to pseudo registers, so don't bother checking. */
+
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int end_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (datum));
+ int i;
+
+ for (i = regno; i < end_regno; i++)
+ if (find_regno_fusage (insn, code, i))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Return true if REGNO, or any overlap of REGNO, of kind CODE is found
+ in the CALL_INSN_FUNCTION_USAGE information of INSN. */
+
+int
+find_regno_fusage (insn, code, regno)
+ rtx insn;
+ enum rtx_code code;
+ int regno;
+{
+ register rtx link;
+
+ /* CALL_INSN_FUNCTION_USAGE information cannot contain references
+ to pseudo registers, so don't bother checking. */
+
+ if (regno >= FIRST_PSEUDO_REGISTER
+ || GET_CODE (insn) != CALL_INSN )
+ return 0;
+
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ {
+ register int regnote;
+ register rtx op;
+
+ if (GET_CODE (op = XEXP (link, 0)) == code
+ && GET_CODE (SET_DEST (op)) == REG
+ && (regnote = REGNO (SET_DEST (op))) <= regno
+ && regnote
+ + HARD_REGNO_NREGS (regnote, GET_MODE (SET_DEST (op)))
+ > regno)
+ return 1;
+ }
+
+ return 0;
+}
\f
/* Remove register note NOTE from the REG_NOTES of INSN. */
abort ();
}
\f
+/* Nonzero if X contains any volatile instructions. These are instructions
+ which may cause unpredictable machine state instructions, and thus no
+ instructions should be moved or combined across them. This includes
+ only volatile asms and UNSPEC_VOLATILE instructions. */
+
+int
+volatile_insn_p (x)
+ rtx x;
+{
+ register RTX_CODE code;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_INT:
+ case CONST:
+ case CONST_DOUBLE:
+ case CC0:
+ case PC:
+ case REG:
+ case SCRATCH:
+ case CLOBBER:
+ case ASM_INPUT:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case CALL:
+ case MEM:
+ return 0;
+
+ case UNSPEC_VOLATILE:
+ /* case TRAP_IF: This isn't clear yet. */
+ return 1;
+
+ case ASM_OPERANDS:
+ if (MEM_VOLATILE_P (x))
+ return 1;
+ }
+
+ /* Recursively scan the operands of this expression. */
+
+ {
+ register char *fmt = GET_RTX_FORMAT (code);
+ register int i;
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (volatile_insn_p (XEXP (x, i)))
+ return 1;
+ }
+ if (fmt[i] == 'E')
+ {
+ register int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (volatile_insn_p (XVECEXP (x, i, j)))
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
/* Nonzero if X contains any volatile memory references
- or volatile ASM_OPERANDS expressions. */
+ UNSPEC_VOLATILE operations or volatile ASM_OPERANDS expressions. */
int
volatile_refs_p (x)
return 0;
case CALL:
+ case UNSPEC_VOLATILE:
/* case TRAP_IF: This isn't clear yet. */
return 1;
case POST_INC:
case POST_DEC:
case CALL:
+ case UNSPEC_VOLATILE:
/* case TRAP_IF: This isn't clear yet. */
return 1;
return 0;
/* Conditional trap can trap! */
+ case UNSPEC_VOLATILE:
case TRAP_IF:
return 1;
we can link this file into other programs. */
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 0)
return 1;
+ case EXPR_LIST:
+ /* An EXPR_LIST is used to represent a function call. This
+ certainly may trap. */
+ return 1;
default:
/* Any floating arithmetic may trap. */
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
case REG:
/* Verify that the register has an entry before trying to access it. */
if (REGNO (x) < nregs && reg_map[REGNO (x)] != 0)
- return reg_map[REGNO (x)];
+ {
+ /* SUBREGs can't be shared. Always return a copy to ensure that if
+ this replacement occurs more than once then each instance will
+ get distinct rtx. */
+ if (GET_CODE (reg_map[REGNO (x)]) == SUBREG)
+ return copy_rtx (reg_map[REGNO (x)]);
+ return reg_map[REGNO (x)];
+ }
return x;
case SUBREG: