#define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (int) (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
-
static struct table_elt *table[HASH_SIZE];
/* Chain of `struct table_elt's made so far for this function
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 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 ((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)
unsigned int regno;
}
}
\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
next = p->next_same_hash;
if (p->in_memory)
{
- if (GET_CODE (p->exp) != MEM)
+ 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);
- else
- {
- /* 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);
- if (true_dependence (x, full_mode, p->canon_exp,
- cse_rtx_varies_p))
- remove_from_table (p, i);
- }
}
}
}
*/
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;
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,
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;
}
}
}
- /* 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);
}
}
&& 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