static void free_insn_expr_list_list PARAMS ((rtx *));
static void clear_modify_mem_tables PARAMS ((void));
static void free_modify_mem_tables PARAMS ((void));
+static rtx gcse_emit_move_after PARAMS ((rtx, rtx, rtx));
\f
/* Entry point for global common subexpression elimination.
F is the first instruction in the function. */
}
}
+/* Emit move from SRC to DEST noting the equivalence with expression computed
+ in INSN. */
+static rtx
+gcse_emit_move_after (src, dest, insn)
+ rtx src, dest, insn;
+{
+ rtx new;
+ rtx set = single_set (insn);
+ rtx note;
+ rtx eqv;
+
+ /* This should never fail since we're creating a reg->reg copy
+ we've verified to be valid. */
+
+ new = emit_insn_after (gen_rtx_SET (VOIDmode, dest, src), insn);
+
+ /* Note the equivalence for local CSE pass. */
+ if ((note = find_reg_equal_equiv_note (insn)))
+ eqv = XEXP (note, 0);
+ else
+ eqv = SET_SRC (set);
+
+ set_unique_reg_note (new, REG_EQUAL, copy_insn_1 (src));
+
+ return new;
+}
+
/* Delete redundant computations.
Deletion is done by changing the insn to copy the `reaching_reg' of
the expression into the result of the SET. It is left to later passes
expr->reaching_reg
= gen_reg_rtx (GET_MODE (SET_DEST (set)));
- /* In theory this should never fail since we're creating
- a reg->reg copy.
-
- However, on the x86 some of the movXX patterns actually
- contain clobbers of scratch regs. This may cause the
- insn created by validate_change to not match any pattern
- and thus cause validate_change to fail. */
- if (validate_change (insn, &SET_SRC (set),
- expr->reaching_reg, 0))
- {
- occr->deleted_p = 1;
- SET_BIT (pre_redundant_insns, INSN_CUID (insn));
- changed = 1;
- gcse_subst_count++;
- }
+ gcse_emit_move_after (expr->reaching_reg, SET_DEST (set), insn);
+ delete_insn (insn);
+ occr->deleted_p = 1;
+ SET_BIT (pre_redundant_insns, INSN_CUID (insn));
+ changed = 1;
+ gcse_subst_count++;
if (gcse_file)
{
expr->reaching_reg
= gen_reg_rtx (GET_MODE (SET_DEST (set)));
- /* In theory this should never fail since we're creating
- a reg->reg copy.
-
- However, on the x86 some of the movXX patterns
- actually contain clobbers of scratch regs. This may
- cause the insn created by validate_change to not
- match any pattern and thus cause validate_change to
- fail. */
- if (validate_change (insn, &SET_SRC (set),
- expr->reaching_reg, 0))
+ gcse_emit_move_after (expr->reaching_reg, SET_DEST (set), insn);
+ delete_insn (insn);
+ occr->deleted_p = 1;
+ if (!insn_inserted_p)
{
- occr->deleted_p = 1;
- if (!insn_inserted_p)
- {
- insert_insn_end_bb (index_map[i], bb, 0);
- insn_inserted_p = 1;
- }
+ insert_insn_end_bb (index_map[i], bb, 0);
+ insn_inserted_p = 1;
}
}
}
static void delete_address_reloads PARAMS ((rtx, rtx));
static void delete_address_reloads_1 PARAMS ((rtx, rtx, rtx));
static rtx inc_for_reload PARAMS ((rtx, rtx, rtx, int));
-static int constraint_accepts_reg_p PARAMS ((const char *, rtx));
static void reload_cse_regs_1 PARAMS ((rtx));
static int reload_cse_noop_set_p PARAMS ((rtx));
static int reload_cse_simplify_set PARAMS ((rtx, rtx));
HOST_WIDE_INT));
static void failed_reload PARAMS ((rtx, int));
static int set_reload_reg PARAMS ((int, int));
-static void reload_cse_delete_noop_set PARAMS ((rtx, rtx));
static void reload_cse_simplify PARAMS ((rtx));
void fixup_abnormal_edges PARAMS ((void));
extern void dump_needs PARAMS ((struct insn_chain *));
&& SET_DEST (PATTERN (temp)) == old
/* Make sure we can access insn_operand_constraint. */
&& asm_noperands (PATTERN (temp)) < 0
- /* This is unsafe if prev insn rejects our reload reg. */
- && constraint_accepts_reg_p (insn_data[recog_memoized (temp)].operand[0].constraint,
- reloadreg)
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences aren't reloaded. */
- && count_occurrences (PATTERN (insn), old, 0) == 1
- /* Don't risk splitting a matching pair of operands. */
- && ! reg_mentioned_p (old, SET_SRC (PATTERN (temp))))
+ && count_occurrences (PATTERN (insn), old, 0) == 1)
{
+ rtx old = SET_DEST (PATTERN (temp));
/* Store into the reload register instead of the pseudo. */
SET_DEST (PATTERN (temp)) = reloadreg;
- /* If the previous insn is an output reload, the source is
- a reload register, and its spill_reg_store entry will
- contain the previous destination. This is now
- invalid. */
- if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
- && REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
+ /* Verify that resulting insn is valid. */
+ extract_insn (temp);
+ if (constrain_operands (1))
{
- spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
- spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
- }
+ /* If the previous insn is an output reload, the source is
+ a reload register, and its spill_reg_store entry will
+ contain the previous destination. This is now
+ invalid. */
+ if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
+ && REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
+ {
+ spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
+ spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
+ }
- /* If these are the only uses of the pseudo reg,
- pretend for GDB it lives in the reload reg we used. */
- if (REG_N_DEATHS (REGNO (old)) == 1
- && REG_N_SETS (REGNO (old)) == 1)
+ /* If these are the only uses of the pseudo reg,
+ pretend for GDB it lives in the reload reg we used. */
+ if (REG_N_DEATHS (REGNO (old)) == 1
+ && REG_N_SETS (REGNO (old)) == 1)
+ {
+ reg_renumber[REGNO (old)] = REGNO (rl->reg_rtx);
+ alter_reg (REGNO (old), -1);
+ }
+ special = 1;
+ }
+ else
{
- reg_renumber[REGNO (old)] = REGNO (rl->reg_rtx);
- alter_reg (REGNO (old), -1);
+ SET_DEST (PATTERN (temp)) = old;
}
- special = 1;
}
}
return store;
}
\f
-/* Return 1 if we are certain that the constraint-string STRING allows
- the hard register REG. Return 0 if we can't be sure of this. */
-
-static int
-constraint_accepts_reg_p (string, reg)
- const char *string;
- rtx reg;
-{
- int value = 0;
- int regno = true_regnum (reg);
- int c;
-
- /* Initialize for first alternative. */
- value = 0;
- /* Check that each alternative contains `g' or `r'. */
- while (1)
- switch (c = *string++)
- {
- case 0:
- /* If an alternative lacks `g' or `r', we lose. */
- return value;
- case ',':
- /* If an alternative lacks `g' or `r', we lose. */
- if (value == 0)
- return 0;
- /* Initialize for next alternative. */
- value = 0;
- break;
- case 'g':
- case 'r':
- /* Any general reg wins for this alternative. */
- if (TEST_HARD_REG_BIT (reg_class_contents[(int) GENERAL_REGS], regno))
- value = 1;
- break;
- default:
- /* Any reg in specified class wins for this alternative. */
- {
- enum reg_class class = REG_CLASS_FROM_LETTER (c);
-
- if (TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno))
- value = 1;
- }
- }
-}
-\f
-/* INSN is a no-op; delete it.
- If this sets the return value of the function, we must keep a USE around,
- in case this is in a different basic block than the final USE. Otherwise,
- we could loose important register lifeness information on
- SMALL_REGISTER_CLASSES machines, where return registers might be used as
- spills: subsequent passes assume that spill registers are dead at the end
- of a basic block.
- VALUE must be the return value in such a case, NULL otherwise. */
-static void
-reload_cse_delete_noop_set (insn, value)
- rtx insn, value;
-{
- bool purge = BLOCK_FOR_INSN (insn)->end == insn;
- if (value)
- {
- PATTERN (insn) = gen_rtx_USE (VOIDmode, value);
- INSN_CODE (insn) = -1;
- REG_NOTES (insn) = NULL_RTX;
- }
- else
- delete_insn (insn);
- if (purge)
- purge_dead_edges (BLOCK_FOR_INSN (insn));
-}
/* See whether a single set SET is a noop. */
static int
if (REG_P (value)
&& ! REG_FUNCTION_VALUE_P (value))
value = 0;
- reload_cse_delete_noop_set (insn, value);
+ delete_insn_and_edges (insn);
return;
}
if (i < 0)
{
- reload_cse_delete_noop_set (insn, value);
+ delete_insn_and_edges (insn);
/* We're done with this insn. */
return;
}