Commit 10d1bb36 by Jan Hubicka Committed by Jan Hubicka

gcse.c (gcse_emit_move_after): New.

	* gcse.c (gcse_emit_move_after): New.
	(pre_delete, hoist_store): Use it.

	* reload1.c (emit_input_reload_insns): Use constrain_operands
	instead of constraint_accepts_reg_p to verify optimization.
	(constraint_accepts_reg_p): Kill

	* reload1.c (reload_cse_delete_noop_set): Kill.
	(reload_cse_simplify): use delte_insn_and_edges.

From-SVN: r54105
parent 8a72fb76
Fri May 31 13:37:54 CEST 2002 Jan Hubicka <jh@suse.cz>
* gcse.c (gcse_emit_move_after): New.
(pre_delete, hoist_store): Use it.
* reload1.c (emit_input_reload_insns): Use constrain_operands
instead of constraint_accepts_reg_p to verify optimization.
(constraint_accepts_reg_p): Kill
* reload1.c (reload_cse_delete_noop_set): Kill.
(reload_cse_simplify): use delte_insn_and_edges.
2002-05-31 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* cfgloop.c (flow_loops_find): Initialize first and last fields
......
......@@ -700,6 +700,7 @@ static void store_motion PARAMS ((void));
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));
/* Entry point for global common subexpression elimination.
F is the first instruction in the function. */
......@@ -4948,6 +4949,33 @@ pre_insert_copies ()
}
}
/* 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
......@@ -4991,21 +5019,12 @@ pre_delete ()
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)
{
......@@ -5827,23 +5846,13 @@ hoist_code ()
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;
}
}
}
......
......@@ -119,6 +119,9 @@ accessor_from_format (c)
case 'B':
return "XBBDEF";
default:
abort ();
}
}
......
......@@ -440,7 +440,6 @@ static void delete_output_reload PARAMS ((rtx, int, int));
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));
......@@ -458,7 +457,6 @@ static HOST_WIDE_INT sext_for_mode PARAMS ((enum machine_mode,
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 *));
......@@ -6383,38 +6381,43 @@ emit_input_reload_insns (chain, rl, old, j)
&& 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;
}
}
......@@ -7980,75 +7983,6 @@ inc_for_reload (reloadreg, in, value, inc_amount)
return store;
}
/* 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;
}
}
}
/* 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
......@@ -8082,7 +8016,7 @@ reload_cse_simplify (insn)
if (REG_P (value)
&& ! REG_FUNCTION_VALUE_P (value))
value = 0;
reload_cse_delete_noop_set (insn, value);
delete_insn_and_edges (insn);
return;
}
......@@ -8119,7 +8053,7 @@ reload_cse_simplify (insn)
if (i < 0)
{
reload_cse_delete_noop_set (insn, value);
delete_insn_and_edges (insn);
/* We're done with this insn. */
return;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment