/* Common subexpression elimination for GNU compiler.
- Copyright (C) 1987, 88, 89, 92-99, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+ 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
rtx const_insn;
rtx comparison_const;
int comparison_qty;
- int first_reg, last_reg;
+ unsigned int first_reg, last_reg;
enum machine_mode mode;
enum rtx_code comparison_code;
};
struct cse_reg_info *next;
/* Search key */
- int regno;
+ unsigned int regno;
/* The quantity number of the register's current contents. */
int reg_qty;
/* The last lookup we did into the cse_reg_info_tree. This allows us
to cache repeated lookups. */
-static int cached_regno;
+static unsigned int cached_regno;
static struct cse_reg_info *cached_cse_reg_info;
/* A HARD_REG_SET containing all the hard registers for which there is
#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)])
+/* Nonzero if this pass has made changes, and therefore it's
+ worthwhile to run the garbage collector. */
+
+static int cse_altered;
+
/* Nonzero if cse has altered conditional jump insns
in such a way that jump optimization should be redone. */
each recording one expression's information.
That expression is in the `exp' field.
+ The canon_exp field contains a canonical (from the point of view of
+ alias analysis) version of the `exp' field.
+
Those elements with the same hash code are chained in both directions
through the `next_same_hash' and `prev_same_hash' fields.
struct table_elt
{
rtx exp;
+ rtx canon_exp;
struct table_elt *next_same_hash;
struct table_elt *prev_same_hash;
struct table_elt *next_same_value;
/* Determine if the quantity number for register X represents a valid index
into the qty_table. */
-#define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (N))
-
-#ifdef ADDRESS_COST
-/* The ADDRESS_COST macro does not deal with ADDRESSOF nodes. But,
- during CSE, such nodes are present. Using an ADDRESSOF node which
- refers to the address of a REG is a good thing because we can then
- turn (MEM (ADDRESSSOF (REG))) into just plain REG. */
-#define CSE_ADDRESS_COST(RTX) \
- ((GET_CODE (RTX) == ADDRESSOF && REG_P (XEXP ((RTX), 0))) \
- ? -1 : ADDRESS_COST(RTX))
-#endif
+#define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (int) (N))
static struct table_elt *table[HASH_SIZE];
static int notreg_cost PARAMS ((rtx));
static void new_basic_block PARAMS ((void));
-static void make_new_qty PARAMS ((int, enum machine_mode));
-static void make_regs_eqv PARAMS ((int, int));
-static void delete_reg_equiv PARAMS ((int));
+static void make_new_qty PARAMS ((unsigned int, enum machine_mode));
+static void make_regs_eqv PARAMS ((unsigned int, unsigned int));
+static void delete_reg_equiv PARAMS ((unsigned int));
static int mention_regs PARAMS ((rtx));
static int insert_regs PARAMS ((rtx, struct table_elt *, int));
static void remove_from_table PARAMS ((struct table_elt *, unsigned));
struct table_elt *));
static void invalidate PARAMS ((rtx, enum machine_mode));
static int cse_rtx_varies_p PARAMS ((rtx));
-static void remove_invalid_refs PARAMS ((int));
-static void remove_invalid_subreg_refs PARAMS ((int, int, enum machine_mode));
+static void remove_invalid_refs PARAMS ((unsigned int));
+static void remove_invalid_subreg_refs PARAMS ((unsigned int, unsigned int,
+ enum machine_mode));
static void rehash_using_reg PARAMS ((rtx));
static void invalidate_memory PARAMS ((void));
static void invalidate_for_call PARAMS ((void));
static unsigned safe_hash PARAMS ((rtx, enum machine_mode));
static int exp_equiv_p PARAMS ((rtx, rtx, int, int));
static rtx canon_reg PARAMS ((rtx, rtx));
-static void find_best_addr PARAMS ((rtx, rtx *));
+static void find_best_addr PARAMS ((rtx, rtx *, enum machine_mode));
static enum rtx_code find_comparison_args PARAMS ((enum rtx_code, rtx *, rtx *,
enum machine_mode *,
enum machine_mode *));
static rtx cse_basic_block PARAMS ((rtx, rtx, struct branch_path *, int));
static void count_reg_usage PARAMS ((rtx, int *, rtx, int));
extern void dump_class PARAMS ((struct table_elt*));
-static struct cse_reg_info* get_cse_reg_info PARAMS ((int));
+static struct cse_reg_info * get_cse_reg_info PARAMS ((unsigned int));
+static int check_dependence PARAMS ((rtx *, void *));
static void flush_hash_table PARAMS ((void));
\f
return total;
}
\f
+/* Return cost of address expression X. Expect that X is propertly formed address
+ reference. */
+int
+address_cost (x, mode)
+ rtx x;
+ enum machine_mode mode;
+{
+ /* The ADDRESS_COST macro does not deal with ADDRESSOF nodes. But,
+ during CSE, such nodes are present. Using an ADDRESSOF node which
+ refers to the address of a REG is a good thing because we can then
+ turn (MEM (ADDRESSSOF (REG))) into just plain REG. */
+
+ if (GET_CODE (x) == ADDRESSOF && REG_P (XEXP ((x), 0)))
+ return -1;
+
+ /* We may be asked for cost of various unusual addresses, such as operands
+ of push instruction. It is not worthwhile to complicate writting
+ of ADDRESS_COST macro by such cases. */
+
+ if (!memory_address_p (mode, x))
+ return 1000;
+#ifdef ADDRESS_COST
+ return ADDRESS_COST (x);
+#else
+ return rtx_cost (x, MEM);
+#endif
+}
+\f
static struct cse_reg_info *
get_cse_reg_info (regno)
- int regno;
+ unsigned int regno;
{
struct cse_reg_info **hash_head = ®_hash[REGHASH_FN (regno)];
struct cse_reg_info *p;
static void
make_new_qty (reg, mode)
- register int reg;
- register enum machine_mode mode;
+ unsigned int reg;
+ enum machine_mode mode;
{
register int q;
register struct qty_table_elem *ent;
static void
make_regs_eqv (new, old)
- register int new, old;
+ unsigned int new, old;
{
- register int lastr, firstr;
- register int q = REG_QTY (old);
- register struct qty_table_elem *ent;
+ unsigned int lastr, firstr;
+ int q = REG_QTY (old);
+ struct qty_table_elem *ent;
ent = &qty_table[q];
static void
delete_reg_equiv (reg)
- register int reg;
+ unsigned int reg;
{
register struct qty_table_elem *ent;
register int q = REG_QTY (reg);
register int p, n;
/* If invalid, do nothing. */
- if (q == reg)
+ if (q == (int) reg)
return;
ent = &qty_table[q];
code = GET_CODE (x);
if (code == REG)
{
- register int regno = REGNO (x);
- register int endregno
+ unsigned int regno = REGNO (x);
+ unsigned int endregno
= regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (regno, GET_MODE (x)));
- int i;
+ unsigned int i;
for (i = regno; i < endregno; i++)
{
if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
{
- int i = REGNO (SUBREG_REG (x));
+ unsigned int i = REGNO (SUBREG_REG (x));
if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
{
{
if (GET_CODE (x) == REG)
{
- register int regno = REGNO (x);
- register int qty_valid;
+ unsigned int regno = REGNO (x);
+ int qty_valid;
/* If REGNO is in the equivalence table already but is of the
wrong mode for that equivalence, don't do anything here. */
else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
&& ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
{
- int regno = REGNO (SUBREG_REG (x));
+ unsigned int regno = REGNO (SUBREG_REG (x));
insert_regs (SUBREG_REG (x), NULL_PTR, 0);
/* Mention_regs checks if REG_TICK is exactly one larger than
if (elt->related_value != 0 && elt->related_value != elt)
{
register struct table_elt *p = elt->related_value;
+
while (p->related_value != elt)
p = p->related_value;
p->related_value = elt->related_value;
if (GET_CODE (x) == REG)
{
- int regno = REGNO (x);
+ unsigned int regno = REGNO (x);
+
/* Don't check the machine mode when comparing registers;
invalidating (REG:SI 0) also invalidates (REG:DF 0). */
for (p = table[hash]; p; p = p->next_same_hash)
rtx x;
enum rtx_code code;
{
- register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) & HASH_MASK,
- GET_MODE (x));
+ register struct table_elt *p
+ = lookup (x, safe_hash (x, VOIDmode) & HASH_MASK, GET_MODE (x));
+
/* If we are looking for a CONST_INT, the mode doesn't really matter, as
long as we are narrowing. So if we looked in vain for a mode narrower
than word_mode before, look for word_mode now. */
return 0;
for (p = p->first_same_value; p; p = p->next_same_value)
- {
- if (GET_CODE (p->exp) == code
- /* Make sure this is a valid entry in the table. */
- && exp_equiv_p (p->exp, p->exp, 1, 0))
- return p->exp;
- }
+ if (GET_CODE (p->exp) == code
+ /* Make sure this is a valid entry in the table. */
+ && exp_equiv_p (p->exp, p->exp, 1, 0))
+ return p->exp;
return 0;
}
/* If X is a hard register, show it is being put in the table. */
if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
{
- int regno = REGNO (x);
- int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- int i;
+ unsigned int regno = REGNO (x);
+ unsigned int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ unsigned int i;
for (i = regno; i < endregno; i++)
- SET_HARD_REG_BIT (hard_regs_in_table, i);
+ SET_HARD_REG_BIT (hard_regs_in_table, i);
}
/* If X is a label, show we recorded it. */
elt = free_element_chain;
if (elt)
- {
- free_element_chain = elt->next_same_hash;
- }
+ free_element_chain = elt->next_same_hash;
else
{
n_elements_made++;
}
elt->exp = x;
+ elt->canon_exp = NULL_RTX;
elt->cost = COST (x);
elt->next_same_value = 0;
elt->prev_same_value = 0;
/* Insert not at head of the class. */
/* Put it after the last element cheaper than X. */
register struct table_elt *p, *next;
+
for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt);
p = next);
+
/* Put it after P and before NEXT. */
elt->next_same_value = next;
if (next)
next->prev_same_value = elt;
+
elt->prev_same_value = p;
p->next_same_value = elt;
elt->first_same_value = classp;
int x_q = REG_QTY (REGNO (x));
struct qty_table_elem *x_ent = &qty_table[x_q];
- x_ent->const_rtx = gen_lowpart_if_possible (GET_MODE (x), p->exp);
+ x_ent->const_rtx
+ = gen_lowpart_if_possible (GET_MODE (x), p->exp);
x_ent->const_insn = this_insn;
break;
}
for (elt = class2; elt; elt = next)
{
- unsigned hash;
+ unsigned int hash;
rtx exp = elt->exp;
enum machine_mode mode = elt->mode;
}
}
\f
+/* Function called for each rtx to check whether true dependence exist. */
+struct check_dependence_data
+{
+ enum machine_mode mode;
+ rtx exp;
+};
+static int
+check_dependence (x, data)
+ rtx *x;
+ void *data;
+{
+ struct check_dependence_data *d = (struct check_dependence_data *) data;
+ if (*x && GET_CODE (*x) == MEM)
+ return true_dependence (d->exp, d->mode, *x, cse_rtx_varies_p);
+ else
+ return 0;
+}
+\f
/* Remove from the hash table, or mark as invalid, all expressions whose
values could be altered by storing in X. X is a register, a subreg, or
a memory reference with nonvarying address (because, when a memory
through the qty number mechanism. Just change the qty number of
the register, mark it as invalid for expressions that refer to it,
and remove it itself. */
- register int regno = REGNO (x);
- register unsigned hash = HASH (x, GET_MODE (x));
+ unsigned int regno = REGNO (x);
+ unsigned int hash = HASH (x, GET_MODE (x));
/* Remove REGNO from any quantity list it might be on and indicate
that its value might have changed. If it is a pseudo, remove its
{
HOST_WIDE_INT in_table
= TEST_HARD_REG_BIT (hard_regs_in_table, regno);
- int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- int tregno, tendregno;
+ unsigned int endregno
+ = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ unsigned int tregno, tendregno, rn;
register struct table_elt *p, *next;
CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
- for (i = regno + 1; i < endregno; i++)
+ for (rn = regno + 1; rn < endregno; rn++)
{
- in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, i);
- CLEAR_HARD_REG_BIT (hard_regs_in_table, i);
- delete_reg_equiv (i);
- REG_TICK (i)++;
+ in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
+ CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
+ delete_reg_equiv (rn);
+ REG_TICK (rn)++;
}
if (in_table)
return;
case MEM:
+ /* Calculate the canonical version of X here so that
+ true_dependence doesn't generate new RTL for X on each call. */
+ x = canon_rtx (x);
+
/* Remove all hash table elements that refer to overlapping pieces of
memory. */
if (full_mode == VOIDmode)
for (p = table[i]; p; p = next)
{
next = p->next_same_hash;
- if (p->in_memory
- && (GET_CODE (p->exp) != MEM
- || true_dependence (x, full_mode, p->exp,
- cse_rtx_varies_p)))
- remove_from_table (p, i);
+ if (p->in_memory)
+ {
+ struct check_dependence_data d;
+
+ /* Just canonicalize the expression once;
+ otherwise each time we call invalidate
+ true_dependence will canonicalize the
+ expression again. */
+ if (!p->canon_exp)
+ p->canon_exp = canon_rtx (p->exp);
+ d.exp = x;
+ d.mode = full_mode;
+ if (for_each_rtx (&p->canon_exp, check_dependence, &d))
+ remove_from_table (p, i);
+ }
}
}
return;
static void
remove_invalid_refs (regno)
- int regno;
+ unsigned int regno;
{
- register int i;
- register struct table_elt *p, *next;
+ unsigned int i;
+ struct table_elt *p, *next;
for (i = 0; i < HASH_SIZE; i++)
for (p = table[i]; p; p = next)
/* Likewise for a subreg with subreg_reg WORD and mode MODE. */
static void
remove_invalid_subreg_refs (regno, word, mode)
- int regno;
- int word;
+ unsigned int regno;
+ unsigned int word;
enum machine_mode mode;
{
- register int i;
- register struct table_elt *p, *next;
- int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
+ unsigned int i;
+ struct table_elt *p, *next;
+ unsigned int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
for (i = 0; i < HASH_SIZE; i++)
for (p = table[i]; p; p = next)
static void
invalidate_for_call ()
{
- int regno, endregno;
- int i;
+ unsigned int regno, endregno;
+ unsigned int i;
unsigned hash;
struct table_elt *p, *next;
int in_table = 0;
{
case REG:
{
- register int regno = REGNO (x);
+ unsigned int regno = REGNO (x);
/* On some machines, we can't record any non-fixed hard register,
because extending its life will cause reload problems. We
do_not_record = 1;
return 0;
}
+
hash += ((unsigned) REG << 7) + (unsigned) REG_QTY (regno);
return hash;
}
hash += canon_hash (XVECEXP (x, i, j), 0);
else if (fmt[i] == 's')
{
- register unsigned char *p = (unsigned char *) XSTR (x, i);
+ register const unsigned char *p =
+ (const unsigned char *) XSTR (x, i);
+
if (p)
while (*p)
hash += *p++;
{
case PC:
case CC0:
- return x == y;
-
case CONST_INT:
- return INTVAL (x) == INTVAL (y);
+ return x == y;
case LABEL_REF:
return XEXP (x, 0) == XEXP (y, 0);
case REG:
{
- int regno = REGNO (y);
- int endregno
+ unsigned int regno = REGNO (y);
+ unsigned int endregno
= regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (regno, GET_MODE (y)));
- int i;
+ unsigned int i;
/* If the quantities are not the same, the expressions are not
equivalent. If there are and we are not to validate, they
*/
static void
-find_best_addr (insn, loc)
+find_best_addr (insn, loc, mode)
rtx insn;
rtx *loc;
+ enum machine_mode mode;
{
struct table_elt *elt;
rtx addr = *loc;
int save_hash_arg_in_memory = hash_arg_in_memory;
int addr_volatile;
int regno;
+ int folded_cost, addr_cost;
unsigned hash;
/* Do not try to replace constant addresses or addresses of local and
{
rtx folded = fold_rtx (copy_rtx (addr), NULL_RTX);
- if (1
-#ifdef ADDRESS_COST
- && (CSE_ADDRESS_COST (folded) < CSE_ADDRESS_COST (addr)
- || (CSE_ADDRESS_COST (folded) == CSE_ADDRESS_COST (addr)
- && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
-#else
+ folded_cost = address_cost (folded, mode);
+ addr_cost = address_cost (addr, mode);
+
+ if ((folded_cost < addr_cost
+ || (folded_cost == addr_cost
+ && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
&& rtx_cost (folded, MEM) < rtx_cost (addr, MEM)
-#endif
&& validate_change (insn, loc, folded, 0))
addr = folded;
}
while (found_better)
{
- int best_addr_cost = CSE_ADDRESS_COST (*loc);
+ int best_addr_cost = address_cost (*loc, mode);
int best_rtx_cost = (elt->cost + 1) >> 1;
+ int exp_cost;
struct table_elt *best_elt = elt;
found_better = 0;
{
if ((GET_CODE (p->exp) == REG
|| exp_equiv_p (p->exp, p->exp, 1, 0))
- && (CSE_ADDRESS_COST (p->exp) < best_addr_cost
- || (CSE_ADDRESS_COST (p->exp) == best_addr_cost
- && (p->cost + 1) >> 1 > best_rtx_cost)))
+ && ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
+ || (exp_cost == best_addr_cost
+ && (p->cost + 1) >> 1 < best_rtx_cost)))
{
found_better = 1;
- best_addr_cost = CSE_ADDRESS_COST (p->exp);
+ best_addr_cost = exp_cost;
best_rtx_cost = (p->cost + 1) >> 1;
best_elt = p;
}
while (found_better)
{
- int best_addr_cost = CSE_ADDRESS_COST (*loc);
+ int best_addr_cost = address_cost (*loc, mode);
int best_rtx_cost = (COST (*loc) + 1) >> 1;
struct table_elt *best_elt = elt;
rtx best_rtx = *loc;
{
rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
p->exp, c);
+ int new_cost;
+ new_cost = address_cost (new, mode);
- if ((CSE_ADDRESS_COST (new) < best_addr_cost
- || (CSE_ADDRESS_COST (new) == best_addr_cost
- && (COST (new) + 1) >> 1 > best_rtx_cost)))
+ if (new_cost < best_addr_cost
+ || (new_cost == best_addr_cost
+ && (COST (new) + 1) >> 1 > best_rtx_cost))
{
found_better = 1;
- best_addr_cost = CSE_ADDRESS_COST (new);
+ best_addr_cost = new_cost;
best_rtx_cost = (COST (new) + 1) >> 1;
best_elt = p;
best_rtx = new;
&& code == LT && STORE_FLAG_VALUE == -1)
#ifdef FLOAT_STORE_FLAG_VALUE
|| (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
x = arg1;
&& code == GE && STORE_FLAG_VALUE == -1)
#ifdef FLOAT_STORE_FLAG_VALUE
|| (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
x = arg1, reverse_code = 1;
#ifdef FLOAT_STORE_FLAG_VALUE
|| (code == LT
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
&& GET_RTX_CLASS (GET_CODE (p->exp)) == '<'))
#ifdef FLOAT_STORE_FLAG_VALUE
|| (code == GE
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
&& GET_RTX_CLASS (GET_CODE (p->exp)) == '<')
best address. Not only don't we care, but we could modify the
MEM in an invalid way since we have no insn to validate against. */
if (insn != 0)
- find_best_addr (insn, &XEXP (x, 0));
+ find_best_addr (insn, &XEXP (x, 0), GET_MODE (x));
{
/* Even if we don't fold in the insn itself,
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
- mode);
+ true = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
false = CONST0_RTX (mode);
}
#endif
struct qty_table_elem *ent = &qty_table[qty];
if ((comparison_dominates_p (ent->comparison_code, code)
- || (comparison_dominates_p (ent->comparison_code,
- reverse_condition (code))
- && ! FLOAT_MODE_P (mode_arg0)))
+ || (! FLOAT_MODE_P (mode_arg0)
+ && comparison_dominates_p (ent->comparison_code,
+ reverse_condition (code))))
&& (rtx_equal_p (ent->comparison_const, folded_arg1)
|| (const_arg1
&& rtx_equal_p (ent->comparison_const,
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
- mode);
+ true = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
false = CONST0_RTX (mode);
}
#endif
const_arg1 ? const_arg1 : folded_arg1);
#ifdef FLOAT_STORE_FLAG_VALUE
if (new != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
- new = ((new == const0_rtx) ? CONST0_RTX (mode)
- : CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE, mode));
+ {
+ if (new == const0_rtx)
+ new = CONST0_RTX (mode);
+ else
+ new = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
+ }
#endif
break;
{
reversed_nonequality = (code != EQ && code != NE);
code = reverse_condition (code);
+
+ /* Don't remember if we can't find the inverse. */
+ if (code == UNKNOWN)
+ return;
}
/* The mode is the mode of the non-constant. */
|| (GET_CODE (trial) == LABEL_REF
&& ! condjump_p (insn))))
{
- /* If TRIAL is a label in front of a jump table, we are
- really falling through the switch (this is how casesi
- insns work), so we must branch around the table. */
- if (GET_CODE (trial) == CODE_LABEL
- && NEXT_INSN (trial) != 0
- && GET_CODE (NEXT_INSN (trial)) == JUMP_INSN
- && (GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_DIFF_VEC
- || GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_VEC))
-
- trial = gen_rtx_LABEL_REF (Pmode, get_label_after (trial));
-
- SET_SRC (sets[i].rtl) = trial;
- cse_jumps_altered = 1;
+ 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);
+
+ cse_jumps_altered = 1;
break;
}
/* If we made a change, recompute SRC values. */
if (src != sets[i].src)
{
+ cse_altered = 1;
do_not_record = 0;
hash_arg_in_memory = 0;
sets[i].src = src;
This code is similar to the REG case in mention_regs,
but it knows that reg_tick has been incremented, and
it leaves reg_in_table as -1 . */
- register int regno = REGNO (x);
- register int endregno
+ unsigned int regno = REGNO (x);
+ unsigned int endregno
= regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (regno, GET_MODE (x)));
- int i;
+ unsigned int i;
for (i = regno; i < endregno; i++)
{
}
}
- /* Special handling for (set REG0 REG1)
- where REG0 is the "cheapest", cheaper than REG1.
- After cse, REG1 will probably not be used in the sequel,
- so (if easily done) change this insn to (set REG1 REG0) and
- replace REG1 with REG0 in the previous insn that computed their value.
- Then REG1 will become a dead store and won't cloud the situation
- for later optimizations.
+ /* Special handling for (set REG0 REG1) where REG0 is the
+ "cheapest", cheaper than REG1. After cse, REG1 will probably not
+ be used in the sequel, so (if easily done) change this insn to
+ (set REG1 REG0) and replace REG1 with REG0 in the previous insn
+ that computed their value. Then REG1 will become a dead store
+ and won't cloud the situation for later optimizations.
Do not make this change if REG1 is a hard register, because it will
then be used in the sequel and we may be changing a two-operand insn
if ((src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
&& ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
{
- rtx prev = PREV_INSN (insn);
- while (prev && GET_CODE (prev) == NOTE)
- prev = PREV_INSN (prev);
+ rtx prev = prev_nonnote_insn (insn);
- if (prev && GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SET
+ if (prev != 0 && GET_CODE (prev) == INSN
+ && GET_CODE (PATTERN (prev)) == SET
&& SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl))
{
rtx dest = SET_DEST (sets[0].rtl);
+ rtx src = SET_SRC (sets[0].rtl);
rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
validate_change (prev, & SET_DEST (PATTERN (prev)), dest, 1);
- validate_change (insn, & SET_DEST (sets[0].rtl),
- SET_SRC (sets[0].rtl), 1);
+ validate_change (insn, & SET_DEST (sets[0].rtl), src, 1);
validate_change (insn, & SET_SRC (sets[0].rtl), dest, 1);
apply_change_group ();
REG_NOTES (prev) = note;
}
- /* If INSN has a REG_EQUAL note, and this note mentions REG0,
- then we must delete it, because the value in REG0 has changed. */
+ /* If INSN has a REG_EQUAL note, and this note mentions
+ REG0, then we must delete it, because the value in
+ REG0 has changed. If the note's value is REG1, we must
+ also delete it because that is now this insn's dest. */
note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- if (note && reg_mentioned_p (dest, XEXP (note, 0)))
+ if (note != 0
+ && (reg_mentioned_p (dest, XEXP (note, 0))
+ || rtx_equal_p (src, XEXP (note, 0))))
remove_note (insn, note);
}
}
insn = f;
while (insn)
{
+ cse_altered = 0;
cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps, after_loop,
flag_cse_skip_blocks);
cse_jumps_altered |= old_cse_jumps_altered;
}
- if (ggc_p)
+ if (ggc_p && cse_altered)
ggc_collect ();
#ifdef USE_C_ALLOCA
/* If we have processed 1,000 insns, flush the hash table to
avoid extreme quadratic behavior. We must not include NOTEs
- in the count since there may be more or them when generating
+ in the count since there may be more of them when generating
debugging information. If we clear the table at different
times, code generated with -g -O might be different than code
generated with -O but not -g.
&& 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))))
+ ;
#ifdef HAVE_cc0
else if (GET_CODE (SET_DEST (PATTERN (insn))) == CC0