/* Analyze RTL for C-Compiler
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 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 "system.h"
#include "toplev.h"
#include "rtl.h"
-
-static void reg_set_p_1 PARAMS ((rtx, rtx, void *));
-static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
-static void reg_set_last_1 PARAMS ((rtx, rtx, void *));
-
+#include "hard-reg-set.h"
/* Forward declarations */
-static int jmp_uses_reg_or_mem PARAMS ((rtx));
+static void set_of_1 PARAMS ((rtx, rtx, void *));
+static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
+static int computed_jump_p_1 PARAMS ((rtx));
+static int operand_preference PARAMS ((rtx));
+static void parms_set PARAMS ((rtx, rtx, void *));
/* Bit flags that specify the machine subtype we are compiling for.
Bits are tested using macros TARGET_... defined in the tm.h file
case QUEUED:
return 1;
+ case ADDRESSOF:
case CONST:
case CONST_INT:
case CONST_DOUBLE:
case REG:
/* As in rtx_varies_p, we have to use the actual rtx, not reg number. */
if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == arg_pointer_rtx || RTX_UNCHANGING_P (x))
+ /* The arg pointer varies if it is not a fixed register. */
+ || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
+ || RTX_UNCHANGING_P (x))
return 0;
#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
/* ??? When call-clobbered, the value is stable modulo the restore
eliminated the frame and/or arg pointer and are using it
for pseudos. */
if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == arg_pointer_rtx)
+ /* The arg pointer varies if it is not a fixed register. */
+ || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
return 0;
if (x == pic_offset_table_rtx
#ifdef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
case LO_SUM:
/* The operand 0 of a LO_SUM is considered constant
- (in fact is it related specifically to operand 1). */
- return rtx_varies_p (XEXP (x, 1), for_alias);
+ (in fact it is related specifically to operand 1)
+ during alias analysis. */
+ return (! for_alias && rtx_varies_p (XEXP (x, 0), for_alias))
+ || rtx_varies_p (XEXP (x, 1), for_alias);
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
switch (code)
{
case SYMBOL_REF:
+ return SYMBOL_REF_WEAK (x);
+
case LABEL_REF:
- /* SYMBOL_REF is problematic due to the possible presence of
- a #pragma weak, but to say that loads from symbols can trap is
- *very* costly. It's not at all clear what's best here. For
- now, we ignore the impact of #pragma weak. */
return 0;
case REG:
/* As in rtx_varies_p, we have to use the actual rtx, not reg number. */
- return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == stack_pointer_rtx || x == arg_pointer_rtx);
+ if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+ || x == stack_pointer_rtx
+ /* The arg pointer varies if it is not a fixed register. */
+ || (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM]))
+ return 0;
+ /* All of the virtual frame registers are stack references. */
+ if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (x) <= LAST_VIRTUAL_REGISTER)
+ return 0;
+ return 1;
case CONST:
return rtx_addr_can_trap_p (XEXP (x, 0));
&& CONSTANT_P (XEXP (x, 1))));
case LO_SUM:
+ case PRE_MODIFY:
return rtx_addr_can_trap_p (XEXP (x, 1));
-
+
+ case PRE_DEC:
+ case PRE_INC:
+ case POST_DEC:
+ case POST_INC:
+ case POST_MODIFY:
+ return rtx_addr_can_trap_p (XEXP (x, 0));
+
default:
break;
}
rtx beg, end;
{
register rtx p;
+ if (beg == end)
+ return 0;
for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))
if (GET_CODE (p) == CODE_LABEL)
return 0;
}
/* Internals of reg_set_between_p. */
-
-static rtx reg_set_reg;
-static int reg_set_flag;
-
-static void
-reg_set_p_1 (x, pat, data)
- rtx x;
- rtx pat ATTRIBUTE_UNUSED;
- void *data ATTRIBUTE_UNUSED;
-{
- /* We don't want to return 1 if X is a MEM that contains a register
- within REG_SET_REG. */
-
- if ((GET_CODE (x) != MEM)
- && reg_overlap_mentioned_p (reg_set_reg, x))
- reg_set_flag = 1;
-}
-
int
reg_set_p (reg, insn)
rtx reg, insn;
body = PATTERN (insn);
}
- reg_set_reg = reg;
- reg_set_flag = 0;
- note_stores (body, reg_set_p_1, NULL);
- return reg_set_flag;
+ return set_of (reg, insn) != NULL_RTX;
}
/* Similar to reg_set_between_p, but check all registers in X. Return 0
*pinsn = NULL_RTX;
}
\f
+/* Helper function for set_of. */
+struct set_of_data
+ {
+ rtx found;
+ rtx pat;
+ };
+
+static void
+set_of_1 (x, pat, data1)
+ rtx x;
+ rtx pat;
+ void *data1;
+{
+ struct set_of_data *data = (struct set_of_data *) (data1);
+ if (rtx_equal_p (x, data->pat)
+ || (GET_CODE (x) != MEM && reg_overlap_mentioned_p (data->pat, x)))
+ data->found = pat;
+}
+
+/* Give an INSN, return a SET or CLOBBER expression that does modify PAT
+ (eighter directly or via STRICT_LOW_PART and similar modifiers). */
+rtx
+set_of (pat, insn)
+ rtx pat, insn;
+{
+ struct set_of_data data;
+ data.found = NULL_RTX;
+ data.pat = pat;
+ note_stores (INSN_P (insn) ? PATTERN (insn) : insn, set_of_1, &data);
+ return data.found;
+}
+\f
/* Given an INSN, return a SET expression if this insn has only a single SET.
It may also have CLOBBERs, USEs, or SET whose output
will not be used, which we ignore. */
return 0;
}
\f
+/* Return nonzero if the destination of SET equals the source
+ and there are no side effects. */
+
+int
+set_noop_p (set)
+ rtx set;
+{
+ rtx src = SET_SRC (set);
+ rtx dst = SET_DEST (set);
+
+ if (side_effects_p (src) || side_effects_p (dst))
+ return 0;
+
+ if (GET_CODE (dst) == MEM && GET_CODE (src) == MEM)
+ return rtx_equal_p (dst, src);
+
+ if (dst == pc_rtx && src == pc_rtx)
+ return 1;
+
+ if (GET_CODE (dst) == SIGN_EXTRACT
+ || GET_CODE (dst) == ZERO_EXTRACT)
+ return rtx_equal_p (XEXP (dst, 0), src)
+ && ! BYTES_BIG_ENDIAN && XEXP (dst, 2) == const0_rtx;
+
+ if (GET_CODE (dst) == STRICT_LOW_PART)
+ dst = XEXP (dst, 0);
+
+ if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
+ {
+ if (SUBREG_BYTE (src) != SUBREG_BYTE (dst))
+ return 0;
+ src = SUBREG_REG (src);
+ dst = SUBREG_REG (dst);
+ }
+
+ return (GET_CODE (src) == REG && GET_CODE (dst) == REG
+ && REGNO (src) == REGNO (dst));
+}
+\f
+/* Return nonzero if an insn consists only of SETs, each of which only sets a
+ value to itself. */
+
+int
+noop_move_p (insn)
+ rtx insn;
+{
+ rtx pat = PATTERN (insn);
+
+ if (INSN_CODE (insn) == NOOP_MOVE_INSN_CODE)
+ return 1;
+
+ /* Insns carrying these notes are useful later on. */
+ if (find_reg_note (insn, REG_EQUAL, NULL_RTX))
+ return 0;
+
+ if (GET_CODE (pat) == SET && set_noop_p (pat))
+ return 1;
+
+ if (GET_CODE (pat) == PARALLEL)
+ {
+ int i;
+ /* If nothing but SETs of registers to themselves,
+ this insn can also be deleted. */
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ {
+ rtx tem = XVECEXP (pat, 0, i);
+
+ if (GET_CODE (tem) == USE
+ || GET_CODE (tem) == CLOBBER)
+ continue;
+
+ if (GET_CODE (tem) != SET || ! set_noop_p (tem))
+ return 0;
+ }
+
+ return 1;
+ }
+ return 0;
+}
+\f
+
/* Return the last thing that X was assigned from before *PINSN. If VALID_TO
is not NULL_RTX then verify that the object is not modified up to VALID_TO.
If the object was modified, if we hit a partial assignment to X, or hit a
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
- unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+ unsigned int inner_regno = subreg_regno (x);
unsigned int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
case SUBREG:
regno = REGNO (SUBREG_REG (x));
if (regno < FIRST_PSEUDO_REGISTER)
- regno += SUBREG_WORD (x);
+ regno = subreg_regno (x);
goto do_reg;
case REG:
do_reg:
endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
- return refers_to_regno_p (regno, endregno, in, NULL_PTR);
+ return refers_to_regno_p (regno, endregno, in, (rtx*)0);
case MEM:
{
case PARALLEL:
{
- int i, n;
-
- /* Check for a NULL entry, used to indicate that the parameter goes
- both on the stack and in registers. */
- if (XEXP (XVECEXP (x, 0, 0), 0))
- i = 0;
- else
- i = 1;
+ int i;
/* If any register in here refers to it we return true. */
- for (n = XVECLEN (x, 0); i < n; ++i)
- if (reg_overlap_mentioned_p (XEXP (XVECEXP (x, 0, i), 0), in))
- return 1;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ if (XEXP (XVECEXP (x, 0, i), 0) != 0
+ && reg_overlap_mentioned_p (XEXP (XVECEXP (x, 0, i), 0), in))
+ return 1;
return 0;
}
abort ();
}
\f
-/* Used for communications between the next few functions. */
-
-static int reg_set_last_unknown;
-static rtx reg_set_last_value;
-static unsigned int reg_set_last_first_regno, reg_set_last_last_regno;
-
-/* Called via note_stores from reg_set_last. */
-
-static void
-reg_set_last_1 (x, pat, data)
- rtx x;
- rtx pat;
- void *data ATTRIBUTE_UNUSED;
-{
- unsigned int first, last;
-
- /* If X is not a register, or is not one in the range we care
- about, ignore. */
- if (GET_CODE (x) != REG)
- return;
-
- first = REGNO (x);
- last = first + (first < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (first, GET_MODE (x)) : 1);
-
- if (first >= reg_set_last_last_regno
- || last <= reg_set_last_first_regno)
- return;
-
- /* If this is a CLOBBER or is some complex LHS, or doesn't modify
- exactly the registers we care about, show we don't know the value. */
- if (GET_CODE (pat) == CLOBBER || SET_DEST (pat) != x
- || first != reg_set_last_first_regno
- || last != reg_set_last_last_regno)
- reg_set_last_unknown = 1;
- else
- reg_set_last_value = SET_SRC (pat);
-}
-
/* Return the last value to which REG was set prior to INSN. If we can't
find it easily, return 0.
{
rtx orig_insn = insn;
- reg_set_last_first_regno = REGNO (x);
-
- reg_set_last_last_regno
- = reg_set_last_first_regno
- + (reg_set_last_first_regno < FIRST_PSEUDO_REGISTER
- ? HARD_REGNO_NREGS (reg_set_last_first_regno, GET_MODE (x)) : 1);
-
- reg_set_last_unknown = 0;
- reg_set_last_value = 0;
-
/* Scan backwards until reg_set_last_1 changed one of the above flags.
Stop when we reach a label or X is a hard reg and we reach a
CALL_INSN (if reg_set_last_last_regno is a hard reg).
for (;
insn && GET_CODE (insn) != CODE_LABEL
&& ! (GET_CODE (insn) == CALL_INSN
- && reg_set_last_last_regno <= FIRST_PSEUDO_REGISTER);
+ && REGNO (x) <= FIRST_PSEUDO_REGISTER);
insn = PREV_INSN (insn))
if (INSN_P (insn))
{
- note_stores (PATTERN (insn), reg_set_last_1, NULL);
- if (reg_set_last_unknown)
- return 0;
- else if (reg_set_last_value)
+ rtx set = set_of (x, insn);
+ /* OK, this function modify our register. See if we understand it. */
+ if (set)
{
- if (CONSTANT_P (reg_set_last_value)
- || ((GET_CODE (reg_set_last_value) == REG
- || GET_CODE (reg_set_last_value) == SUBREG)
- && ! reg_set_between_p (reg_set_last_value,
+ rtx last_value;
+ if (GET_CODE (set) != SET || SET_DEST (set) != x)
+ return 0;
+ last_value = SET_SRC (x);
+ if (CONSTANT_P (last_value)
+ || ((GET_CODE (last_value) == REG
+ || GET_CODE (last_value) == SUBREG)
+ && ! reg_set_between_p (last_value,
insn, orig_insn)))
- return reg_set_last_value;
+ return last_value;
else
return 0;
}
void (*fun) PARAMS ((rtx, rtx, void *));
void *data;
{
+ int i;
+
if (GET_CODE (x) == COND_EXEC)
x = COND_EXEC_CODE (x);
+
if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
{
register rtx dest = SET_DEST (x);
+
while ((GET_CODE (dest) == SUBREG
&& (GET_CODE (SUBREG_REG (dest)) != REG
|| REGNO (SUBREG_REG (dest)) >= FIRST_PSEUDO_REGISTER))
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
- if (GET_CODE (dest) == PARALLEL
- && GET_MODE (dest) == BLKmode)
+ /* If we have a PARALLEL, SET_DEST is a list of EXPR_LIST expressions,
+ each of whose first operand is a register. We can't know what
+ precisely is being set in these cases, so make up a CLOBBER to pass
+ to the function. */
+ if (GET_CODE (dest) == PARALLEL)
{
- register int i;
for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
- (*fun) (SET_DEST (XVECEXP (dest, 0, i)), x, data);
+ if (XEXP (XVECEXP (dest, 0, i), 0) != 0)
+ (*fun) (XEXP (XVECEXP (dest, 0, i), 0),
+ gen_rtx_CLOBBER (VOIDmode,
+ XEXP (XVECEXP (dest, 0, i), 0)),
+ data);
}
else
(*fun) (dest, x, data);
}
+
else if (GET_CODE (x) == PARALLEL)
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ note_stores (XVECEXP (x, 0, i), fun, data);
+}
+\f
+/* Like notes_stores, but call FUN for each expression that is being
+ referenced in PBODY, a pointer to the PATTERN of an insn. We only call
+ FUN for each expression, not any interior subexpressions. FUN receives a
+ pointer to the expression and the DATA passed to this function.
+
+ Note that this is not quite the same test as that done in reg_referenced_p
+ since that considers something as being referenced if it is being
+ partially set, while we do not. */
+
+void
+note_uses (pbody, fun, data)
+ rtx *pbody;
+ void (*fun) PARAMS ((rtx *, void *));
+ void *data;
+{
+ rtx body = *pbody;
+ int i;
+
+ switch (GET_CODE (body))
{
- register int i;
- for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- {
- register rtx y = XVECEXP (x, 0, i);
- if (GET_CODE (y) == COND_EXEC)
- y = COND_EXEC_CODE (y);
- if (GET_CODE (y) == SET || GET_CODE (y) == CLOBBER)
- {
- register rtx dest = SET_DEST (y);
- while ((GET_CODE (dest) == SUBREG
- && (GET_CODE (SUBREG_REG (dest)) != REG
- || (REGNO (SUBREG_REG (dest))
- >= FIRST_PSEUDO_REGISTER)))
- || GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == SIGN_EXTRACT
- || GET_CODE (dest) == STRICT_LOW_PART)
- dest = XEXP (dest, 0);
- if (GET_CODE (dest) == PARALLEL
- && GET_MODE (dest) == BLKmode)
- {
- register int i;
+ case COND_EXEC:
+ (*fun) (&COND_EXEC_TEST (body), data);
+ note_uses (&COND_EXEC_CODE (body), fun, data);
+ return;
- for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
- (*fun) (SET_DEST (XVECEXP (dest, 0, i)), y, data);
- }
- else
- (*fun) (dest, y, data);
- }
- }
+ case PARALLEL:
+ for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
+ note_uses (&XVECEXP (body, 0, i), fun, data);
+ return;
+
+ case USE:
+ (*fun) (&XEXP (body, 0), data);
+ return;
+
+ case ASM_OPERANDS:
+ for (i = ASM_OPERANDS_INPUT_LENGTH (body) - 1; i >= 0; i--)
+ (*fun) (&ASM_OPERANDS_INPUT (body, i), data);
+ return;
+
+ case TRAP_IF:
+ (*fun) (&TRAP_CONDITION (body), data);
+ return;
+
+ case UNSPEC:
+ case UNSPEC_VOLATILE:
+ for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
+ (*fun) (&XVECEXP (body, 0, i), data);
+ return;
+
+ case CLOBBER:
+ if (GET_CODE (XEXP (body, 0)) == MEM)
+ (*fun) (&XEXP (XEXP (body, 0), 0), data);
+ return;
+
+ case SET:
+ {
+ rtx dest = SET_DEST (body);
+
+ /* For sets we replace everything in source plus registers in memory
+ expression in store and operands of a ZERO_EXTRACT. */
+ (*fun) (&SET_SRC (body), data);
+
+ if (GET_CODE (dest) == ZERO_EXTRACT)
+ {
+ (*fun) (&XEXP (dest, 1), data);
+ (*fun) (&XEXP (dest, 2), data);
+ }
+
+ while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+
+ if (GET_CODE (dest) == MEM)
+ (*fun) (&XEXP (dest, 0), data);
+ }
+ return;
+
+ default:
+ /* All the other possibilities never store. */
+ (*fun) (pbody, data);
+ return;
}
}
\f
return 0;
}
+/* Return a REG_EQUIV or REG_EQUAL note if insn has only a single set and
+ has such a note. */
+
+rtx
+find_reg_equal_equiv_note (insn)
+ rtx insn;
+{
+ rtx note;
+
+ if (single_set (insn) == 0)
+ return 0;
+ else if ((note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
+ return note;
+ else
+ return find_reg_note (insn, REG_EQUAL, NULL_RTX);
+}
+
/* Return true if DATUM, or any overlap of DATUM, of kind CODE is found
in the CALL_INSN_FUNCTION_USAGE information of INSN. */
abort ();
}
-/* Search LISTP (an EXPR_LIST) for NODE and remove NODE from the list
- if it is found.
+/* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
+ remove that entry from the list if it is found.
- A simple equality test is used to determine if NODE is on the
- EXPR_LIST. */
+ A simple equality test is used to determine if NODE matches. */
void
remove_node_from_expr_list (node, listp)
return;
}
+
+ prev = temp;
temp = XEXP (temp, 1);
}
}
return 1;
break;
+ case NEG:
+ case ABS:
+ /* These operations don't trap even with floating point. */
+ break;
+
default:
/* Any floating arithmetic may trap. */
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
register const char *fmt;
/* The following prevents loops occurrence when we change MEM in
- CONST_DOUBLE onto the same CONST_DOUBLE. */
+ CONST_DOUBLE onto the same CONST_DOUBLE. */
if (x != 0 && GET_CODE (x) == CONST_DOUBLE)
return x;
&& GET_CODE (reg_map[REGNO (SUBREG_REG (x))]) == SUBREG)
{
rtx map_val = reg_map[REGNO (SUBREG_REG (x))];
- rtx map_inner = SUBREG_REG (map_val);
-
- if (GET_MODE (x) == GET_MODE (map_inner))
- return map_inner;
- else
- {
- /* We cannot call gen_rtx here since we may be linked with
- genattrtab.c. */
- /* Let's try clobbering the incoming SUBREG and see
- if this is really safe. */
- SUBREG_REG (x) = map_inner;
- SUBREG_WORD (x) += SUBREG_WORD (map_val);
- return x;
-#if 0
- rtx new = rtx_alloc (SUBREG);
- PUT_MODE (new, GET_MODE (x));
- SUBREG_REG (new) = map_inner;
- SUBREG_WORD (new) = SUBREG_WORD (x) + SUBREG_WORD (map_val);
-#endif
- }
+ return simplify_gen_subreg (GET_MODE (x), map_val,
+ GET_MODE (SUBREG_REG (x)),
+ SUBREG_BYTE (x));
}
break;
return x;
}
-/* Return 1 if X, the SRC_SRC of SET of (pc) contain a REG or MEM that is
- not in the constant pool and not in the condition of an IF_THEN_ELSE. */
+/* A subroutine of computed_jump_p, return 1 if X contains a REG or MEM or
+ constant that is not in the constant pool and not in the condition
+ of an IF_THEN_ELSE. */
static int
-jmp_uses_reg_or_mem (x)
+computed_jump_p_1 (x)
rtx x;
{
enum rtx_code code = GET_CODE (x);
switch (code)
{
- case CONST:
case LABEL_REF:
case PC:
return 0;
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
case REG:
return 1;
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
case IF_THEN_ELSE:
- return (jmp_uses_reg_or_mem (XEXP (x, 1))
- || jmp_uses_reg_or_mem (XEXP (x, 2)));
-
- case PLUS: case MINUS: case MULT:
- return (jmp_uses_reg_or_mem (XEXP (x, 0))
- || jmp_uses_reg_or_mem (XEXP (x, 1)));
+ return (computed_jump_p_1 (XEXP (x, 1))
+ || computed_jump_p_1 (XEXP (x, 2)));
default:
break;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e'
- && jmp_uses_reg_or_mem (XEXP (x, i)))
+ && computed_jump_p_1 (XEXP (x, i)))
return 1;
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
- if (jmp_uses_reg_or_mem (XVECEXP (x, i, j)))
+ if (computed_jump_p_1 (XVECEXP (x, i, j)))
return 1;
}
{
rtx pat = PATTERN (insn);
- if (GET_CODE (pat) == PARALLEL)
+ if (find_reg_note (insn, REG_LABEL, NULL_RTX))
+ return 0;
+ else if (GET_CODE (pat) == PARALLEL)
{
int len = XVECLEN (pat, 0);
int has_use_labelref = 0;
for (i = len - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (pat, 0, i)) == SET
&& SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
- && jmp_uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
+ && computed_jump_p_1 (SET_SRC (XVECEXP (pat, 0, i))))
return 1;
}
else if (GET_CODE (pat) == SET
&& SET_DEST (pat) == pc_rtx
- && jmp_uses_reg_or_mem (SET_SRC (pat)))
+ && computed_jump_p_1 (SET_SRC (pat)))
return 1;
}
return 0;
{
int result;
int length;
- const char* format;
+ const char *format;
int i;
/* Call F on X. */
- result = (*f)(x, data);
+ result = (*f) (x, data);
if (result == -1)
/* Do not traverse sub-expressions. */
return 0;
return NULL_RTX;
}
+/* Return a value indicating whether OP, an operand of a commutative
+ operation, is preferred as the first or second operand. The higher
+ the value, the stronger the preference for being the first operand.
+ We use negative values to indicate a preference for the first operand
+ and positive values for the second operand. */
+
+static int
+operand_preference (op)
+ rtx op;
+{
+ /* Constants always come the second operand. Prefer "nice" constants. */
+ if (GET_CODE (op) == CONST_INT)
+ return -5;
+ if (GET_CODE (op) == CONST_DOUBLE)
+ return -4;
+ if (CONSTANT_P (op))
+ return -3;
+
+ /* SUBREGs of objects should come second. */
+ if (GET_CODE (op) == SUBREG
+ && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op))) == 'o')
+ return -2;
+
+ /* If only one operand is a `neg', `not',
+ `mult', `plus', or `minus' expression, it will be the first
+ operand. */
+ if (GET_CODE (op) == NEG || GET_CODE (op) == NOT
+ || GET_CODE (op) == MULT || GET_CODE (op) == PLUS
+ || GET_CODE (op) == MINUS)
+ return 2;
+
+ /* Complex expressions should be the first, so decrease priority
+ of objects. */
+ if (GET_RTX_CLASS (GET_CODE (op)) == 'o')
+ return -1;
+ return 0;
+}
+
+/* Return 1 iff it is neccesary to swap operands of commutative operation
+ in order to canonicalize expression. */
+
+int
+swap_commutative_operands_p (x, y)
+ rtx x, y;
+{
+ return operand_preference (x) < operand_preference (y);
+}
/* Return 1 if X is an autoincrement side effect and the register is
not the stack pointer. */
end of the extended sequence.
For now, this function only checks that the region contains whole
- exception regiongs, but it could be extended to check additional
+ exception regions, but it could be extended to check additional
conditions as well. */
int
}
return 0;
}
+
+/* This function returns the regno offset of a subreg expression.
+ xregno - A regno of an inner hard subreg_reg (or what will become one).
+ xmode - The mode of xregno.
+ offset - The byte offset.
+ ymode - The mode of a top level SUBREG (or what may become one).
+ RETURN - The regno offset which would be used.
+ This function can be overridden by defining SUBREG_REGNO_OFFSET,
+ taking the same parameters. */
+unsigned int
+subreg_regno_offset (xregno, xmode, offset, ymode)
+ unsigned int xregno;
+ enum machine_mode xmode;
+ unsigned int offset;
+ enum machine_mode ymode;
+{
+ unsigned ret;
+ int nregs_xmode, nregs_ymode;
+ int mode_multiple, nregs_multiple;
+ int y_offset;
+
+/* Check for an override, and use it instead. */
+#ifdef SUBREG_REGNO_OFFSET
+ ret = SUBREG_REGNO_OFFSET (xregno, xmode, offset, ymode)
+#else
+ if (xregno >= FIRST_PSEUDO_REGISTER)
+ abort ();
+
+ nregs_xmode = HARD_REGNO_NREGS (xregno, xmode);
+ nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
+ if (offset == 0 || nregs_xmode == nregs_ymode)
+ return 0;
+
+ /* size of ymode must not be greater than the size of xmode. */
+ mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
+ if (mode_multiple == 0)
+ abort ();
+
+ y_offset = offset / GET_MODE_SIZE (ymode);
+ nregs_multiple = nregs_xmode / nregs_ymode;
+ ret = (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
+#endif
+
+ return ret;
+}
+
+/* Return the final regno that a subreg expression refers to. */
+unsigned int
+subreg_regno (x)
+ rtx x;
+{
+ unsigned int ret;
+ rtx subreg = SUBREG_REG (x);
+ int regno = REGNO (subreg);
+
+ ret = regno + subreg_regno_offset (regno,
+ GET_MODE (subreg),
+ SUBREG_BYTE (x),
+ GET_MODE (x));
+ return ret;
+
+}
+struct parms_set_data
+{
+ int nregs;
+ HARD_REG_SET regs;
+};
+
+/* Helper function for noticing stores to parameter registers. */
+static void
+parms_set (x, pat, data)
+ rtx x, pat ATTRIBUTE_UNUSED;
+ void *data;
+{
+ struct parms_set_data *d = data;
+ if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER
+ && TEST_HARD_REG_BIT (d->regs, REGNO (x)))
+ {
+ CLEAR_HARD_REG_BIT (d->regs, REGNO (x));
+ d->nregs--;
+ }
+}
+
+/* Look backward for first parameter to be loaded.
+ Do not skip BOUNDARY. */
+rtx
+find_first_parameter_load (call_insn, boundary)
+ rtx call_insn, boundary;
+{
+ struct parms_set_data parm;
+ rtx p, before;
+
+ /* Since different machines initialize their parameter registers
+ in different orders, assume nothing. Collect the set of all
+ parameter registers. */
+ CLEAR_HARD_REG_SET (parm.regs);
+ parm.nregs = 0;
+ for (p = CALL_INSN_FUNCTION_USAGE (call_insn); p; p = XEXP (p, 1))
+ if (GET_CODE (XEXP (p, 0)) == USE
+ && GET_CODE (XEXP (XEXP (p, 0), 0)) == REG)
+ {
+ if (REGNO (XEXP (XEXP (p, 0), 0)) >= FIRST_PSEUDO_REGISTER)
+ abort ();
+
+ /* We only care about registers which can hold function
+ arguments. */
+ if (!FUNCTION_ARG_REGNO_P (REGNO (XEXP (XEXP (p, 0), 0))))
+ continue;
+
+ SET_HARD_REG_BIT (parm.regs, REGNO (XEXP (XEXP (p, 0), 0)));
+ parm.nregs++;
+ }
+ before = call_insn;
+
+ /* Search backward for the first set of a register in this set. */
+ while (parm.nregs && before != boundary)
+ {
+ before = PREV_INSN (before);
+
+ /* It is possible that some loads got CSEed from one call to
+ another. Stop in that case. */
+ if (GET_CODE (before) == CALL_INSN)
+ break;
+
+ /* Our caller needs either ensure that we will find all sets
+ (in case code has not been optimized yet), or take care
+ for possible labels in a way by setting boundary to preceeding
+ CODE_LABEL. */
+ if (GET_CODE (before) == CODE_LABEL)
+ {
+ if (before != boundary)
+ abort ();
+ break;
+ }
+
+ if (INSN_P (before))
+ note_stores (PATTERN (before), parms_set, &parm);
+ }
+ return before;
+}