/* Common subexpression elimination for GNU compiler.
Copyright (C) 1987, 1988, 1989, 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.
static int cse_jumps_altered;
-/* Nonzero if we put a LABEL_REF into the hash table. Since we may have put
- it into an INSN without a REG_LABEL, we have to rerun jump after CSE
- to put in the note. */
+/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
+ REG_LABEL, we have to rerun jump after CSE to put in the note. */
static int recorded_label_ref;
+/* Says which LABEL_REF was put in the hash table. Used to see if we need
+ to set the above flag. */
+static rtx new_label_ref;
+
/* canon_hash stores 1 in do_not_record
if it notices a reference to CC0, PC, or some other volatile
subexpression. */
/* If reg_tick has been incremented more than once since
reg_in_table was last set, that means that the entire
register has been set before, so discard anything memorized
- for the entrire register, including all SUBREG expressions. */
+ for the entire register, including all SUBREG expressions. */
if (REG_IN_TABLE (i) != REG_TICK (i) - 1)
remove_invalid_refs (i);
else
- remove_invalid_subreg_refs (i, SUBREG_WORD (x), GET_MODE (x));
+ remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x));
}
REG_IN_TABLE (i) = REG_TICK (i);
{
if (GET_CODE (XEXP (x, 0)) == REG
&& ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
- if (insert_regs (XEXP (x, 0), NULL_PTR, 0))
+ if (insert_regs (XEXP (x, 0), NULL, 0))
{
rehash_using_reg (XEXP (x, 0));
changed = 1;
if (GET_CODE (XEXP (x, 1)) == REG
&& ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
- if (insert_regs (XEXP (x, 1), NULL_PTR, 0))
+ if (insert_regs (XEXP (x, 1), NULL, 0))
{
rehash_using_reg (XEXP (x, 1));
changed = 1;
else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
&& ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
{
- insert_regs (SUBREG_REG (x), NULL_PTR, 0);
+ insert_regs (SUBREG_REG (x), NULL, 0);
mention_regs (x);
return 1;
}
if (GET_CODE (x) == LABEL_REF
|| (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF))
- recorded_label_ref = 1;
+ new_label_ref = x;
/* Put an element for X into the right hash bucket. */
subhash = safe_hash (subexp, mode) & HASH_MASK;
subelt = lookup (subexp, subhash, mode);
if (subelt == 0)
- subelt = insert (subexp, NULL_PTR, subhash, mode);
+ subelt = insert (subexp, NULL, subhash, mode);
/* Initialize SUBELT's circular chain if it has none. */
if (subelt->related_value == 0)
subelt->related_value = subelt;
{
next = p->next_same_hash;
if (GET_CODE (p->exp) != REG
- && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+ && refers_to_regno_p (regno, regno + 1, p->exp, (rtx*)0))
remove_from_table (p, i);
}
}
-/* Likewise for a subreg with subreg_reg WORD and mode MODE. */
+/* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
+ and mode MODE. */
static void
-remove_invalid_subreg_refs (regno, word, mode)
+remove_invalid_subreg_refs (regno, offset, mode)
unsigned int regno;
- unsigned int word;
+ unsigned int offset;
enum machine_mode mode;
{
unsigned int i;
struct table_elt *p, *next;
- unsigned int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
+ unsigned int end = offset + (GET_MODE_SIZE (mode) - 1);
for (i = 0; i < HASH_SIZE; i++)
for (p = table[i]; p; p = next)
{
- rtx exp;
+ rtx exp = p->exp;
next = p->next_same_hash;
- exp = p->exp;
- if (GET_CODE (p->exp) != REG
+ if (GET_CODE (exp) != REG
&& (GET_CODE (exp) != SUBREG
|| GET_CODE (SUBREG_REG (exp)) != REG
|| REGNO (SUBREG_REG (exp)) != regno
- || (((SUBREG_WORD (exp)
- + (GET_MODE_SIZE (GET_MODE (exp)) - 1) / UNITS_PER_WORD)
- >= word)
- && SUBREG_WORD (exp) <= end))
- && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+ || (((SUBREG_BYTE (exp)
+ + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
+ && SUBREG_BYTE (exp) <= end))
+ && refers_to_regno_p (regno, regno + 1, p->exp, (rtx*)0))
remove_from_table (p, i);
}
}
if (GET_CODE (SUBREG_REG (x)) == REG)
{
hash += (((unsigned) SUBREG << 7)
- + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
+ + REGNO (SUBREG_REG (x))
+ + (SUBREG_BYTE (x) / UNITS_PER_WORD));
return hash;
}
break;
|| exp_equiv_p (p->exp, p->exp, 1, 0))
&& ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
|| (exp_cost == best_addr_cost
- && (p->cost + 1) >> 1 < best_rtx_cost)))
+ && ((p->cost + 1) >> 1) > best_rtx_cost)))
{
found_better = 1;
best_addr_cost = exp_cost;
if (folded_arg0 != SUBREG_REG (x))
{
- new = 0;
-
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) == UNITS_PER_WORD
- && GET_MODE (SUBREG_REG (x)) != VOIDmode)
- new = operand_subword (folded_arg0, SUBREG_WORD (x), 0,
- GET_MODE (SUBREG_REG (x)));
- if (new == 0 && subreg_lowpart_p (x))
- new = gen_lowpart_if_possible (mode, folded_arg0);
+ new = simplify_subreg (mode, folded_arg0,
+ GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
if (new)
return new;
}
if (const_arg0 == 0 || const_arg1 == 0)
{
struct table_elt *p0, *p1;
- rtx true = const_true_rtx, false = const0_rtx;
+ rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
enum machine_mode mode_arg1;
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = (CONST_DOUBLE_FROM_REAL_VALUE
+ true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
(FLOAT_STORE_FLAG_VALUE (mode), mode));
- false = CONST0_RTX (mode);
+ false_rtx = CONST0_RTX (mode);
}
#endif
|| GET_CODE (folded_arg0) == CONST))
{
if (code == EQ)
- return false;
+ return false_rtx;
else if (code == NE)
- return true;
+ return true_rtx;
}
/* See if the two operands are the same. */
{
/* Sadly two equal NaNs are not equivalent. */
if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || ! FLOAT_MODE_P (mode_arg0) || flag_fast_math)
+ || ! FLOAT_MODE_P (mode_arg0)
+ || flag_unsafe_math_optimizations)
return ((code == EQ || code == LE || code == GE
|| code == LEU || code == GEU || code == UNEQ
|| code == UNLE || code == UNGE || code == ORDERED)
- ? true : false);
+ ? true_rtx : false_rtx);
/* Take care for the FP compares we can resolve. */
if (code == UNEQ || code == UNLE || code == UNGE)
- return true;
+ return true_rtx;
if (code == LTGT || code == LT || code == GT)
- return false;
+ return false_rtx;
}
/* If FOLDED_ARG0 is a register, see if the comparison we are
|| (GET_CODE (folded_arg1) == REG
&& (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
return (comparison_dominates_p (ent->comparison_code, code)
- ? true : false);
+ ? true_rtx : false_rtx);
}
}
}
int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
&& (INTVAL (inner_const)
& ((HOST_WIDE_INT) 1 << sign_bitnum)));
- rtx true = const_true_rtx, false = const0_rtx;
+ rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = (CONST_DOUBLE_FROM_REAL_VALUE
+ true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
(FLOAT_STORE_FLAG_VALUE (mode), mode));
- false = CONST0_RTX (mode);
+ false_rtx = CONST0_RTX (mode);
}
#endif
switch (code)
{
case EQ:
- return false;
+ return false_rtx;
case NE:
- return true;
+ return true_rtx;
case LT: case LE:
if (has_sign)
- return true;
+ return true_rtx;
break;
case GT: case GE:
if (has_sign)
- return false;
+ return false_rtx;
break;
default:
break;
offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
- MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
if (BYTES_BIG_ENDIAN)
- /* Adjust the address so that the address-after-the-data is
- unchanged. */
- offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
+ {
+ /* Adjust the address so that the address-after-the-data is
+ unchanged. */
+ offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
+ - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
+ }
new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
if (! memory_address_p (mode, XEXP (new, 0)))
return 0;
new quantity number. */
if (op0_elt == 0)
{
- if (insert_regs (op0, NULL_PTR, 0))
+ if (insert_regs (op0, NULL, 0))
{
rehash_using_reg (op0);
op0_hash = HASH (op0, mode);
op1_hash = HASH (op1,mode);
}
- op0_elt = insert (op0, NULL_PTR, op0_hash, mode);
+ op0_elt = insert (op0, NULL, op0_hash, mode);
op0_elt->in_memory = op0_in_memory;
}
/* Put OP1 in the hash table so it gets a new quantity number. */
if (op1_elt == 0)
{
- if (insert_regs (op1, NULL_PTR, 0))
+ if (insert_regs (op1, NULL, 0))
{
rehash_using_reg (op1);
op1_hash = HASH (op1, mode);
}
- op1_elt = insert (op1, NULL_PTR, op1_hash, mode);
+ op1_elt = insert (op1, NULL, op1_hash, mode);
op1_elt->in_memory = op1_in_memory;
}
if (op0_elt == 0)
{
- if (insert_regs (op0, NULL_PTR, 0))
+ if (insert_regs (op0, NULL, 0))
{
rehash_using_reg (op0);
op0_hash = HASH (op0, mode);
}
- op0_elt = insert (op0, NULL_PTR, op0_hash, mode);
+ op0_elt = insert (op0, NULL, op0_hash, mode);
op0_elt->in_memory = op0_in_memory;
}
if (op1_elt == 0)
{
- if (insert_regs (op1, NULL_PTR, 0))
+ if (insert_regs (op1, NULL, 0))
{
rehash_using_reg (op1);
op1_hash = HASH (op1, mode);
}
- op1_elt = insert (op1, NULL_PTR, op1_hash, mode);
+ op1_elt = insert (op1, NULL, op1_hash, mode);
op1_elt->in_memory = op1_in_memory;
}
int src_eqv_in_memory = 0;
unsigned src_eqv_hash = 0;
- struct set *sets = (struct set *) NULL_PTR;
+ struct set *sets = (struct set *) 0;
this_insn = insn;
if (GET_CODE (insn) == CALL_INSN)
{
for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
- if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
- invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+ {
+ if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
+ invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+ XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+ }
}
if (GET_CODE (x) == SET)
sets[i].src_in_memory = hash_arg_in_memory;
/* If SRC is a MEM, there is a REG_EQUIV note for SRC, and DEST is
- a pseudo that is set more than once, do not record SRC. Using
- SRC as a replacement for anything else will be incorrect in that
- situation. Note that this usually occurs only for stack slots,
- in which case all the RTL would be referring to SRC, so we don't
- lose any optimization opportunities by not having SRC in the
- hash table. */
+ a pseudo, do not record SRC. Using SRC as a replacement for
+ anything else will be incorrect in that situation. Note that
+ this usually occurs only for stack slots, in which case all the
+ RTL would be referring to SRC, so we don't lose any optimization
+ opportunities by not having SRC in the hash table. */
if (GET_CODE (src) == MEM
- && find_reg_note (insn, REG_EQUIV, src) != 0
+ && find_reg_note (insn, REG_EQUIV, NULL_RTX) != 0
&& GET_CODE (dest) == REG
- && REGNO (dest) >= FIRST_PSEUDO_REGISTER
- && REG_N_SETS (REGNO (dest)) != 1)
+ && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
sets[i].src_volatile = 1;
#if 0
check for this separately here. We will delete such an
insn below.
- Tablejump insns contain a USE of the table, so simply replacing
- the operand with the constant won't match. This is simply an
- unconditional branch, however, and is therefore valid. Just
- insert the substitution here and we will delete and re-emit
- the insn later. */
-
+ For other cases such as a table jump or conditional jump
+ where we know the ultimate target, go ahead and replace the
+ operand. While that may not make a valid insn, we will
+ reemit the jump below (and also insert any necessary
+ barriers). */
if (n_sets == 1 && dest == pc_rtx
&& (trial == pc_rtx
|| (GET_CODE (trial) == LABEL_REF
&& ! condjump_p (insn))))
{
- if (trial == pc_rtx)
- {
- SET_SRC (sets[i].rtl) = trial;
- cse_jumps_altered = 1;
- break;
- }
-
- PATTERN (insn) = gen_jump (XEXP (trial, 0));
- INSN_CODE (insn) = -1;
-
- if (NEXT_INSN (insn) != 0
- && GET_CODE (NEXT_INSN (insn)) != BARRIER)
- emit_barrier_after (insn);
-
+ SET_SRC (sets[i].rtl) = trial;
cse_jumps_altered = 1;
break;
}
}
/* If this SET is now setting PC to a label, we know it used to
- be a conditional or computed branch. So we see if we can follow
- it. If it was a computed branch, delete it and re-emit. */
+ be a conditional or computed branch. */
else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
{
- /* If this is not in the format for a simple branch and
- we are the only SET in it, re-emit it. */
- if (! simplejump_p (insn) && n_sets == 1)
+ /* We reemit the jump in as many cases as possible just in
+ case the form of an unconditional jump is significantly
+ different than a computed jump or conditional jump.
+
+ If this insn has multiple sets, then reemitting the
+ jump is nontrivial. So instead we just force rerecognition
+ and hope for the best. */
+ if (n_sets == 1)
{
rtx new = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
JUMP_LABEL (new) = XEXP (src, 0);
insn = new;
}
else
- /* Otherwise, force rerecognition, since it probably had
- a different pattern before.
- This shouldn't really be necessary, since whatever
- changed the source value above should have done this.
- Until the right place is found, might as well do this here. */
INSN_CODE (insn) = -1;
never_reached_warning (insn);
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
#endif
-#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
+#if !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
&& ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
#endif
)
libcall_insn = 0;
}
+ new_label_ref = 0;
cse_insn (insn, libcall_insn);
+
+ /* If this insn uses a LABEL_REF and there isn't a REG_LABEL
+ note for it, we must rerun jump since it needs to place the
+ note. If this is a LABEL_REF for a CODE_LABEL that isn't in
+ the insn chain, don't do this since no REG_LABEL will be added. */
+ if (new_label_ref != 0 && INSN_UID (XEXP (new_label_ref, 0)) != 0
+ && reg_mentioned_p (new_label_ref, PATTERN (insn))
+ && ! find_reg_note (insn, REG_LABEL, XEXP (new_label_ref, 0)))
+ recorded_label_ref = 1;
}
/* If INSN is now an unconditional jump, skip to the end of our
live_insn = ! dead_libcall;
else if (GET_CODE (PATTERN (insn)) == SET)
{
- if ((GET_CODE (SET_DEST (PATTERN (insn))) == REG
- || GET_CODE (SET_DEST (PATTERN (insn))) == SUBREG)
- && rtx_equal_p (SET_DEST (PATTERN (insn)),
- SET_SRC (PATTERN (insn))))
- ;
- else if (GET_CODE (SET_DEST (PATTERN (insn))) == STRICT_LOW_PART
- && rtx_equal_p (XEXP (SET_DEST (PATTERN (insn)), 0),
- SET_SRC (PATTERN (insn))))
+ if (set_noop_p (PATTERN (insn)))
;
#ifdef HAVE_cc0
if (GET_CODE (elt) == SET)
{
- if ((GET_CODE (SET_DEST (elt)) == REG
- || GET_CODE (SET_DEST (elt)) == SUBREG)
- && rtx_equal_p (SET_DEST (elt), SET_SRC (elt)))
+ if (set_noop_p (elt))
;
#ifdef HAVE_cc0