Commit ae9dd7f3 by Bernd Schmidt Committed by Bernd Schmidt

Fix latent LRA remat issue (PR68730)

	PR rtl-optimization/68730
	* lra-remat.c (insn_to_cand_activation): New static variable.
	(lra_remat): Allocate and free it.
	(create_cand): New arg activation. Initialize a field in
	insn_to_cand_activation if it is nonnull.
	(create_cands): Pass the activation insn to create_cand when making
	a candidate involving an output reload.  Reorganize code a little.
	(do_remat): Keep track of active status of candidates in a separate
	bitmap.

From-SVN: r233215
parent cc07da33
2016-02-08 Bernd Schmidt <bschmidt@redhat.com>
PR rtl-optimization/68730
* lra-remat.c (insn_to_cand_activation): New static variable.
(lra_remat): Allocate and free it.
(create_cand): New arg activation. Initialize a field in
insn_to_cand_activation if it is nonnull.
(create_cands): Pass the activation insn to create_cand when making
a candidate involving an output reload. Reorganize code a little.
(do_remat): Keep track of active status of candidates in a separate
bitmap.
2016-02-08 Richard Biener <rguenther@suse.de> 2016-02-08 Richard Biener <rguenther@suse.de>
PR tree-optimization/69719 PR tree-optimization/69719
...@@ -30,7 +42,6 @@ ...@@ -30,7 +42,6 @@
* tree-ssa-scopedtables.c * tree-ssa-scopedtables.c
(const_and_copies::record_const_or_copy_raw): New, factored out of (const_and_copies::record_const_or_copy_raw): New, factored out of
(const_and_copies::record_const_or_copy): Call new member function. (const_and_copies::record_const_or_copy): Call new member function.
2016-02-05 Jeff Law <law@redhat.com> 2016-02-05 Jeff Law <law@redhat.com>
......
...@@ -112,6 +112,10 @@ static vec<cand_t> all_cands; ...@@ -112,6 +112,10 @@ static vec<cand_t> all_cands;
/* Map: insn -> candidate representing it. It is null if the insn can /* Map: insn -> candidate representing it. It is null if the insn can
not be used for rematerialization. */ not be used for rematerialization. */
static cand_t *insn_to_cand; static cand_t *insn_to_cand;
/* A secondary map, for candidates that involve two insns, where the
second one makes the equivalence. The candidate must not be used
before seeing this activation insn. */
static cand_t *insn_to_cand_activation;
/* Map regno -> candidates can be used for the regno /* Map regno -> candidates can be used for the regno
rematerialization. */ rematerialization. */
...@@ -461,7 +465,7 @@ operand_to_remat (rtx_insn *insn) ...@@ -461,7 +465,7 @@ operand_to_remat (rtx_insn *insn)
REGNO. Insert the candidate into the table and set up the REGNO. Insert the candidate into the table and set up the
corresponding INSN_TO_CAND element. */ corresponding INSN_TO_CAND element. */
static void static void
create_cand (rtx_insn *insn, int nop, int regno) create_cand (rtx_insn *insn, int nop, int regno, rtx_insn *activation = NULL)
{ {
lra_insn_recog_data_t id = lra_get_insn_recog_data (insn); lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
rtx reg = *id->operand_loc[nop]; rtx reg = *id->operand_loc[nop];
...@@ -486,6 +490,8 @@ create_cand (rtx_insn *insn, int nop, int regno) ...@@ -486,6 +490,8 @@ create_cand (rtx_insn *insn, int nop, int regno)
cand->next_regno_cand = regno_cands[cand->regno]; cand->next_regno_cand = regno_cands[cand->regno];
regno_cands[cand->regno] = cand; regno_cands[cand->regno] = cand;
} }
if (activation)
insn_to_cand_activation[INSN_UID (activation)] = cand_in_table;
} }
/* Create rematerialization candidates (inserting them into the /* Create rematerialization candidates (inserting them into the
...@@ -504,43 +510,55 @@ create_cands (void) ...@@ -504,43 +510,55 @@ create_cands (void)
/* Create candidates. */ /* Create candidates. */
regno_potential_cand = XCNEWVEC (struct potential_cand, max_reg_num ()); regno_potential_cand = XCNEWVEC (struct potential_cand, max_reg_num ());
for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn)) if (NONDEBUG_INSN_P (insn))
{ {
rtx set;
int src_regno, dst_regno;
rtx_insn *insn2;
lra_insn_recog_data_t id = lra_get_insn_recog_data (insn); lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
int nop = operand_to_remat (insn); int keep_regno = -1;
int regno = -1; rtx set = single_set (insn);
int nop;
if ((set = single_set (insn)) != NULL
&& REG_P (SET_SRC (set)) && REG_P (SET_DEST (set)) /* See if this is an output reload for a previous insn. */
&& ((src_regno = REGNO (SET_SRC (set))) if (set != NULL
>= lra_constraint_new_regno_start) && REG_P (SET_SRC (set)) && REG_P (SET_DEST (set)))
&& (dst_regno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER {
&& reg_renumber[dst_regno] < 0 rtx dstreg = SET_DEST (set);
&& (insn2 = regno_potential_cand[src_regno].insn) != NULL int src_regno = REGNO (SET_SRC (set));
&& BLOCK_FOR_INSN (insn2) == BLOCK_FOR_INSN (insn)) int dst_regno = REGNO (dstreg);
/* It is an output reload insn after insn can be rtx_insn *insn2 = regno_potential_cand[src_regno].insn;
rematerialized (potential candidate). */
create_cand (insn2, regno_potential_cand[src_regno].nop, dst_regno); if (insn2 != NULL
if (nop < 0) && dst_regno >= FIRST_PSEUDO_REGISTER
goto fail; && reg_renumber[dst_regno] < 0
gcc_assert (REG_P (*id->operand_loc[nop])); && BLOCK_FOR_INSN (insn2) == BLOCK_FOR_INSN (insn))
regno = REGNO (*id->operand_loc[nop]); {
gcc_assert (regno >= FIRST_PSEUDO_REGISTER); create_cand (insn2, regno_potential_cand[src_regno].nop,
if (reg_renumber[regno] < 0) dst_regno, insn);
create_cand (insn, nop, regno); goto done;
else }
}
nop = operand_to_remat (insn);
if (nop >= 0)
{ {
regno_potential_cand[regno].insn = insn; gcc_assert (REG_P (*id->operand_loc[nop]));
regno_potential_cand[regno].nop = nop; int regno = REGNO (*id->operand_loc[nop]);
goto fail; gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
/* If we're setting an unrenumbered pseudo, make a candidate immediately.
If it's an output reload register, save it for later; the code above
looks for output reload insns later on. */
if (reg_renumber[regno] < 0)
create_cand (insn, nop, regno);
else if (regno >= lra_constraint_new_regno_start)
{
regno_potential_cand[regno].insn = insn;
regno_potential_cand[regno].nop = nop;
keep_regno = regno;
}
} }
regno = -1;
fail: done:
for (struct lra_insn_reg *reg = id->regs; reg != NULL; reg = reg->next) for (struct lra_insn_reg *reg = id->regs; reg != NULL; reg = reg->next)
if (reg->type != OP_IN && reg->regno != regno if (reg->type != OP_IN && reg->regno != keep_regno
&& reg->regno >= FIRST_PSEUDO_REGISTER) && reg->regno >= FIRST_PSEUDO_REGISTER)
regno_potential_cand[reg->regno].insn = NULL; regno_potential_cand[reg->regno].insn = NULL;
} }
...@@ -1072,16 +1090,21 @@ do_remat (void) ...@@ -1072,16 +1090,21 @@ do_remat (void)
rtx_insn *insn; rtx_insn *insn;
basic_block bb; basic_block bb;
bitmap_head avail_cands; bitmap_head avail_cands;
bitmap_head active_cands;
bool changed_p = false; bool changed_p = false;
/* Living hard regs and hard registers of living pseudos. */ /* Living hard regs and hard registers of living pseudos. */
HARD_REG_SET live_hard_regs; HARD_REG_SET live_hard_regs;
bitmap_initialize (&avail_cands, &reg_obstack); bitmap_initialize (&avail_cands, &reg_obstack);
bitmap_initialize (&active_cands, &reg_obstack);
FOR_EACH_BB_FN (bb, cfun) FOR_EACH_BB_FN (bb, cfun)
{ {
REG_SET_TO_HARD_REG_SET (live_hard_regs, df_get_live_out (bb)); REG_SET_TO_HARD_REG_SET (live_hard_regs, df_get_live_out (bb));
bitmap_and (&avail_cands, &get_remat_bb_data (bb)->avin_cands, bitmap_and (&avail_cands, &get_remat_bb_data (bb)->avin_cands,
&get_remat_bb_data (bb)->livein_cands); &get_remat_bb_data (bb)->livein_cands);
/* Activating insns are always in the same block as their corresponding
remat insn, so at the start of a block the two bitsets are equal. */
bitmap_copy (&active_cands, &avail_cands);
FOR_BB_INSNS (bb, insn) FOR_BB_INSNS (bb, insn)
{ {
if (!NONDEBUG_INSN_P (insn)) if (!NONDEBUG_INSN_P (insn))
...@@ -1115,7 +1138,8 @@ do_remat (void) ...@@ -1115,7 +1138,8 @@ do_remat (void)
for (cand = regno_cands[src_regno]; for (cand = regno_cands[src_regno];
cand != NULL; cand != NULL;
cand = cand->next_regno_cand) cand = cand->next_regno_cand)
if (bitmap_bit_p (&avail_cands, cand->index)) if (bitmap_bit_p (&avail_cands, cand->index)
&& bitmap_bit_p (&active_cands, cand->index))
break; break;
} }
int i, hard_regno, nregs; int i, hard_regno, nregs;
...@@ -1209,9 +1233,23 @@ do_remat (void) ...@@ -1209,9 +1233,23 @@ do_remat (void)
} }
bitmap_and_compl_into (&avail_cands, &temp_bitmap); bitmap_and_compl_into (&avail_cands, &temp_bitmap);
if ((cand = insn_to_cand[INSN_UID (insn)]) != NULL)
bitmap_set_bit (&avail_cands, cand->index); /* Now see whether a candidate is made active or available
by this insn. */
cand = insn_to_cand_activation[INSN_UID (insn)];
if (cand)
bitmap_set_bit (&active_cands, cand->index);
cand = insn_to_cand[INSN_UID (insn)];
if (cand != NULL)
{
bitmap_set_bit (&avail_cands, cand->index);
if (cand->reload_regno == -1)
bitmap_set_bit (&active_cands, cand->index);
else
bitmap_clear_bit (&active_cands, cand->index);
}
if (remat_insn != NULL) if (remat_insn != NULL)
{ {
HOST_WIDE_INT sp_offset_change = cand_sp_offset - id->sp_offset; HOST_WIDE_INT sp_offset_change = cand_sp_offset - id->sp_offset;
...@@ -1258,6 +1296,7 @@ do_remat (void) ...@@ -1258,6 +1296,7 @@ do_remat (void)
} }
} }
bitmap_clear (&avail_cands); bitmap_clear (&avail_cands);
bitmap_clear (&active_cands);
return changed_p; return changed_p;
} }
...@@ -1286,6 +1325,7 @@ lra_remat (void) ...@@ -1286,6 +1325,7 @@ lra_remat (void)
lra_rematerialization_iter); lra_rematerialization_iter);
timevar_push (TV_LRA_REMAT); timevar_push (TV_LRA_REMAT);
insn_to_cand = XCNEWVEC (cand_t, get_max_uid ()); insn_to_cand = XCNEWVEC (cand_t, get_max_uid ());
insn_to_cand_activation = XCNEWVEC (cand_t, get_max_uid ());
regno_cands = XCNEWVEC (cand_t, max_regno); regno_cands = XCNEWVEC (cand_t, max_regno);
all_cands.create (8000); all_cands.create (8000);
call_used_regs_arr_len = 0; call_used_regs_arr_len = 0;
...@@ -1314,6 +1354,7 @@ lra_remat (void) ...@@ -1314,6 +1354,7 @@ lra_remat (void)
bitmap_clear (&all_blocks); bitmap_clear (&all_blocks);
free (regno_cands); free (regno_cands);
free (insn_to_cand); free (insn_to_cand);
free (insn_to_cand_activation);
timevar_pop (TV_LRA_REMAT); timevar_pop (TV_LRA_REMAT);
return result; return result;
} }
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