Commit b00544fa by Alan Modra Committed by Alan Modra

ira.c use DF infrastructure for combine_and_move_insns

This patch actually improves generated code, because REG_DEAD notes
used by the old insn scan are not always present.  On x86_64, see
gcc/wide-int-print.o:print_hex for an example of a function that is
smaller and uses one less callee saved reg.

	* ira.c (combine_and_move_insns): Rather than scanning insns,
	use DF infrastucture to find use and def insns.

From-SVN: r235660
parent 10e04446
2016-04-30 Alan Modra <amodra@gmail.com> 2016-04-30 Alan Modra <amodra@gmail.com>
* ira.c (combine_and_move_insns): Rather than scanning insns,
use DF infrastucture to find use and def insns.
2016-04-30 Alan Modra <amodra@gmail.com>
ira.c (combine_and_move_insns): Move invariant conditions.. ira.c (combine_and_move_insns): Move invariant conditions..
(ira.c): ..to here. Call combine_and_move_insns before (ira.c): ..to here. Call combine_and_move_insns before
add_store_equivs. Call grow_reg_equivs later. Allocate add_store_equivs. Call grow_reg_equivs later. Allocate
......
...@@ -3630,142 +3630,119 @@ add_store_equivs (void) ...@@ -3630,142 +3630,119 @@ add_store_equivs (void)
static void static void
combine_and_move_insns (void) combine_and_move_insns (void)
{ {
rtx_insn *insn;
basic_block bb;
int loop_depth;
bitmap cleared_regs = BITMAP_ALLOC (NULL); bitmap cleared_regs = BITMAP_ALLOC (NULL);
int max = max_reg_num ();
FOR_EACH_BB_REVERSE_FN (bb, cfun) for (int regno = FIRST_PSEUDO_REGISTER; regno < max; regno++)
{ {
loop_depth = bb_loop_depth (bb); if (!reg_equiv[regno].replace)
for (insn = BB_END (bb); continue;
insn != PREV_INSN (BB_HEAD (bb));
insn = PREV_INSN (insn))
{
rtx link;
if (! INSN_P (insn)) rtx_insn *use_insn = 0;
for (df_ref use = DF_REG_USE_CHAIN (regno);
use;
use = DF_REF_NEXT_REG (use))
if (DF_REF_INSN_INFO (use))
{
if (DEBUG_INSN_P (DF_REF_INSN (use)))
continue; continue;
gcc_assert (!use_insn);
use_insn = DF_REF_INSN (use);
}
gcc_assert (use_insn);
/* Don't substitute into jumps. indirect_jump_optimize does /* Don't substitute into jumps. indirect_jump_optimize does
this for anything we are prepared to handle. */ this for anything we are prepared to handle. */
if (JUMP_P (insn)) if (JUMP_P (use_insn))
continue; continue;
for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) df_ref def = DF_REG_DEF_CHAIN (regno);
{ gcc_assert (DF_REG_DEF_COUNT (regno) == 1 && DF_REF_INSN_INFO (def));
if (REG_NOTE_KIND (link) == REG_DEAD rtx_insn *def_insn = DF_REF_INSN (def);
/* Make sure this insn still refers to the register. */
&& reg_mentioned_p (XEXP (link, 0), PATTERN (insn)))
{
int regno = REGNO (XEXP (link, 0));
rtx equiv_insn;
if (! reg_equiv[regno].replace /* We may not move instructions that can throw, since that
|| reg_equiv[regno].loop_depth < (short) loop_depth) changes basic block boundaries and we are not prepared to
adjust the CFG to match. */
if (can_throw_internal (def_insn))
continue; continue;
/* reg_equiv[REGNO].replace gets set only when basic_block use_bb = BLOCK_FOR_INSN (use_insn);
REG_N_REFS[REGNO] is 2, i.e. the register is set basic_block def_bb = BLOCK_FOR_INSN (def_insn);
once and used once. (If it were only set, but if (bb_loop_depth (use_bb) > bb_loop_depth (def_bb))
not used, flow would have deleted the setting
insns.) Hence there can only be one insn in
reg_equiv[REGNO].init_insns. */
gcc_assert (reg_equiv[regno].init_insns
&& !XEXP (reg_equiv[regno].init_insns, 1));
equiv_insn = XEXP (reg_equiv[regno].init_insns, 0);
/* We may not move instructions that can throw, since
that changes basic block boundaries and we are not
prepared to adjust the CFG to match. */
if (can_throw_internal (equiv_insn))
continue; continue;
if (asm_noperands (PATTERN (equiv_insn)) < 0 if (asm_noperands (PATTERN (def_insn)) < 0
&& validate_replace_rtx (regno_reg_rtx[regno], && validate_replace_rtx (regno_reg_rtx[regno],
*(reg_equiv[regno].src_p), insn)) *reg_equiv[regno].src_p, use_insn))
{ {
rtx equiv_link; rtx link;
rtx last_link; /* Append the REG_DEAD notes from def_insn. */
rtx note; for (rtx *p = &REG_NOTES (def_insn); (link = *p) != 0; )
/* Find the last note. */
for (last_link = link; XEXP (last_link, 1);
last_link = XEXP (last_link, 1))
;
/* Append the REG_DEAD notes from equiv_insn. */
equiv_link = REG_NOTES (equiv_insn);
while (equiv_link)
{ {
note = equiv_link; if (REG_NOTE_KIND (XEXP (link, 0)) == REG_DEAD)
equiv_link = XEXP (equiv_link, 1);
if (REG_NOTE_KIND (note) == REG_DEAD)
{ {
remove_note (equiv_insn, note); *p = XEXP (link, 1);
XEXP (last_link, 1) = note; XEXP (link, 1) = REG_NOTES (use_insn);
XEXP (note, 1) = NULL_RTX; REG_NOTES (use_insn) = link;
last_link = note;
} }
else
p = &XEXP (link, 1);
} }
remove_death (regno, insn); remove_death (regno, use_insn);
SET_REG_N_REFS (regno, 0); SET_REG_N_REFS (regno, 0);
REG_FREQ (regno) = 0; REG_FREQ (regno) = 0;
delete_insn (equiv_insn); delete_insn (def_insn);
reg_equiv[regno].init_insns
= reg_equiv[regno].init_insns->next ();
reg_equiv[regno].init_insns = NULL;
ira_reg_equiv[regno].init_insns = NULL; ira_reg_equiv[regno].init_insns = NULL;
bitmap_set_bit (cleared_regs, regno); bitmap_set_bit (cleared_regs, regno);
} }
/* Move the initialization of the register to just before /* Move the initialization of the register to just before
INSN. Update the flow information. */ USE_INSN. Update the flow information. */
else if (prev_nondebug_insn (insn) != equiv_insn) else if (prev_nondebug_insn (use_insn) != def_insn)
{ {
rtx_insn *new_insn; rtx_insn *new_insn;
new_insn = emit_insn_before (PATTERN (equiv_insn), insn); new_insn = emit_insn_before (PATTERN (def_insn), use_insn);
REG_NOTES (new_insn) = REG_NOTES (equiv_insn); REG_NOTES (new_insn) = REG_NOTES (def_insn);
REG_NOTES (equiv_insn) = 0; REG_NOTES (def_insn) = 0;
/* Rescan it to process the notes. */ /* Rescan it to process the notes. */
df_insn_rescan (new_insn); df_insn_rescan (new_insn);
/* Make sure this insn is recognized before /* Make sure this insn is recognized before reload begins,
reload begins, otherwise otherwise eliminate_regs_in_insn will die. */
eliminate_regs_in_insn will die. */ INSN_CODE (new_insn) = INSN_CODE (def_insn);
INSN_CODE (new_insn) = INSN_CODE (equiv_insn);
delete_insn (equiv_insn); delete_insn (def_insn);
XEXP (reg_equiv[regno].init_insns, 0) = new_insn; XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
REG_BASIC_BLOCK (regno) = bb->index; REG_BASIC_BLOCK (regno) = use_bb->index;
REG_N_CALLS_CROSSED (regno) = 0; REG_N_CALLS_CROSSED (regno) = 0;
REG_FREQ_CALLS_CROSSED (regno) = 0; REG_FREQ_CALLS_CROSSED (regno) = 0;
REG_N_THROWING_CALLS_CROSSED (regno) = 0; REG_N_THROWING_CALLS_CROSSED (regno) = 0;
REG_LIVE_LENGTH (regno) = 2; REG_LIVE_LENGTH (regno) = 2;
if (insn == BB_HEAD (bb)) if (use_insn == BB_HEAD (use_bb))
BB_HEAD (bb) = PREV_INSN (insn); BB_HEAD (use_bb) = new_insn;
ira_reg_equiv[regno].init_insns ira_reg_equiv[regno].init_insns
= gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX); = gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX);
bitmap_set_bit (cleared_regs, regno); bitmap_set_bit (cleared_regs, regno);
} }
} }
}
}
}
if (!bitmap_empty_p (cleared_regs)) if (!bitmap_empty_p (cleared_regs))
{ {
basic_block bb;
FOR_EACH_BB_FN (bb, cfun) FOR_EACH_BB_FN (bb, cfun)
{ {
bitmap_and_compl_into (DF_LR_IN (bb), cleared_regs); bitmap_and_compl_into (DF_LR_IN (bb), cleared_regs);
bitmap_and_compl_into (DF_LR_OUT (bb), cleared_regs); bitmap_and_compl_into (DF_LR_OUT (bb), cleared_regs);
if (! df_live) if (!df_live)
continue; continue;
bitmap_and_compl_into (DF_LIVE_IN (bb), cleared_regs); bitmap_and_compl_into (DF_LIVE_IN (bb), cleared_regs);
bitmap_and_compl_into (DF_LIVE_OUT (bb), cleared_regs); bitmap_and_compl_into (DF_LIVE_OUT (bb), cleared_regs);
...@@ -3773,7 +3750,7 @@ combine_and_move_insns (void) ...@@ -3773,7 +3750,7 @@ combine_and_move_insns (void)
/* Last pass - adjust debug insns referencing cleared regs. */ /* Last pass - adjust debug insns referencing cleared regs. */
if (MAY_HAVE_DEBUG_INSNS) if (MAY_HAVE_DEBUG_INSNS)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (DEBUG_INSN_P (insn)) if (DEBUG_INSN_P (insn))
{ {
rtx old_loc = INSN_VAR_LOCATION_LOC (insn); rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
......
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