re PR rtl-optimization/42216 (changes in scheduling regress 464.h264ref 20%)

PR rtl-opt/42216
	* regrename.c: Error out if MAX_RECOG_OPERANDS is larger than
	HOST_BITS_PER_WIDE_INT.
	(verify_reg_in_set): New function, broken out of verify_reg_tracked.
	(verify_reg_tracked): Use it.
	(scan_rtx_reg): When seeing a use involving a superset of the
	registers in an existing chain, enlarge that chain.  Otherwise,
	allow subsets and set fail_current_block for all other kinds of
	overlap.
	(hide_operands): New argument UNTRACKED_OPERANDS; callers changed.
	Do not modify operands when the bit with the corresponding number
	is set in that bitmap.
	(build_def_use): When we see matching operands with different
	modes, don't set fail_current_block, but keep track of such
	operands in a bitmap if their registers aren't already tracked
	in an open chain.  Pass this bitmap to all hide_operands calls.

From-SVN: r155134
This commit is contained in:
Bernd Schmidt 2009-12-10 18:03:05 +00:00 committed by Bernd Schmidt
parent 574f366488
commit d435810e76
2 changed files with 95 additions and 34 deletions

View File

@ -1,3 +1,22 @@
2009-12-10 Bernd Schmidt <bernd.schmidt@analog.com>
PR rtl-opt/42216
* regrename.c: Error out if MAX_RECOG_OPERANDS is larger than
HOST_BITS_PER_WIDE_INT.
(verify_reg_in_set): New function, broken out of verify_reg_tracked.
(verify_reg_tracked): Use it.
(scan_rtx_reg): When seeing a use involving a superset of the
registers in an existing chain, enlarge that chain. Otherwise,
allow subsets and set fail_current_block for all other kinds of
overlap.
(hide_operands): New argument UNTRACKED_OPERANDS; callers changed.
Do not modify operands when the bit with the corresponding number
is set in that bitmap.
(build_def_use): When we see matching operands with different
modes, don't set fail_current_block, but keep track of such
operands in a bitmap if their registers aren't already tracked
in an open chain. Pass this bitmap to all hide_operands calls.
2009-12-10 Richard Guenther <rguenther@suse.de>
PR tree-optimization/42337

View File

@ -40,6 +40,10 @@
#include "tree-pass.h"
#include "df.h"
#if HOST_BITS_PER_WIDE_INT <= MAX_RECOG_OPERANDS
#error "Use a different bitmap implementation for untracked_operands."
#endif
/* We keep linked lists of DU_HEAD structures, each of which describes
a chain of occurrences of a reg. */
struct du_head
@ -434,21 +438,23 @@ static unsigned current_id;
static struct du_head *open_chains;
static struct du_head *closed_chains;
/* Conflict bitmaps, tracking the live chains and the live hard registers.
The bits set in open_chains_set always match the list found in
/* Bitmap of open chains. The bits set always match the list found in
open_chains. */
static bitmap_head open_chains_set;
static HARD_REG_SET live_hard_regs;
/* Record the registers being tracked in open_chains. The intersection
between this and live_hard_regs is empty. */
/* Record the registers being tracked in open_chains. */
static HARD_REG_SET live_in_chains;
/* Return true if OP is a reg that is being tracked already in some form.
May set fail_current_block if it sees an unhandled case of overlap. */
/* Record the registers that are live but not tracked. The intersection
between this and live_in_chains is empty. */
static HARD_REG_SET live_hard_regs;
/* Return true if OP is a reg for which all bits are set in PSET, false
if all bits are clear.
In other cases, set fail_current_block and return false. */
static bool
verify_reg_tracked (rtx op)
verify_reg_in_set (rtx op, HARD_REG_SET *pset)
{
unsigned regno, nregs;
bool all_live, all_dead;
@ -459,7 +465,7 @@ verify_reg_tracked (rtx op)
nregs = hard_regno_nregs[regno][GET_MODE (op)];
all_live = all_dead = true;
while (nregs-- > 0)
if (TEST_HARD_REG_BIT (live_hard_regs, regno + nregs))
if (TEST_HARD_REG_BIT (*pset, regno + nregs))
all_dead = false;
else
all_live = false;
@ -468,26 +474,19 @@ verify_reg_tracked (rtx op)
fail_current_block = true;
return false;
}
if (all_live)
return true;
nregs = hard_regno_nregs[regno][GET_MODE (op)];
all_live = all_dead = true;
while (nregs-- > 0)
if (TEST_HARD_REG_BIT (live_in_chains, regno + nregs))
all_dead = false;
else
all_live = false;
if (!all_dead && !all_live)
{
fail_current_block = true;
return false;
}
return all_live;
}
/* Return true if OP is a reg that is being tracked already in some form.
May set fail_current_block if it sees an unhandled case of overlap. */
static bool
verify_reg_tracked (rtx op)
{
return (verify_reg_in_set (op, &live_hard_regs)
|| verify_reg_in_set (op, &live_in_chains));
}
/* Called through note_stores. DATA points to a rtx_code, either SET or
CLOBBER, which tells us which kind of rtx to look at. If we have a
match, record the set register in live_hard_regs and in the hard_conflicts
@ -584,6 +583,8 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
&& head->nregs == this_nregs);
int superset = (this_regno <= head->regno
&& this_regno + this_nregs >= head->regno + head->nregs);
int subset = (this_regno >= head->regno
&& this_regno + this_nregs <= head->regno + head->nregs);
if (head->terminated
|| head->regno + head->nregs <= this_regno
@ -607,6 +608,25 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
reg_names[head->regno], head->id, INSN_UID (insn),
scan_actions_name[(int) action]);
head->cannot_rename = 1;
if (superset)
{
unsigned nregs = this_nregs;
head->regno = this_regno;
head->nregs = this_nregs;
while (nregs-- > 0)
SET_HARD_REG_BIT (live_in_chains, head->regno + nregs);
if (dump_file)
fprintf (dump_file,
"Widening register in chain %s (%d) at insn %d\n",
reg_names[head->regno], head->id, INSN_UID (insn));
}
else if (!subset)
{
fail_current_block = true;
if (dump_file)
fprintf (dump_file,
"Failing basic block due to unhandled overlap\n");
}
}
else
{
@ -919,12 +939,13 @@ scan_rtx (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
/* Hide operands of the current insn (of which there are N_OPS) by
substituting cc0 for them.
Previous values are stored in the OLD_OPERANDS and OLD_DUPS.
For every bit set in DO_NOT_HIDE, we leave the operand alone.
If INOUT_AND_EC_ONLY is set, we only do this for OP_INOUT type operands
and earlyclobbers. */
static void
hide_operands (int n_ops, rtx *old_operands, rtx *old_dups,
bool inout_and_ec_only)
unsigned HOST_WIDE_INT do_not_hide, bool inout_and_ec_only)
{
int i;
int alt = which_alternative;
@ -936,6 +957,8 @@ hide_operands (int n_ops, rtx *old_operands, rtx *old_dups,
reachable by proper operands. */
if (recog_data.constraints[i][0] == '\0')
continue;
if (do_not_hide & (1 << i))
continue;
if (!inout_and_ec_only || recog_data.operand_type[i] == OP_INOUT
|| recog_op_alt[i][alt].earlyclobber)
*recog_data.operand_loc[i] = cc0_rtx;
@ -944,6 +967,8 @@ hide_operands (int n_ops, rtx *old_operands, rtx *old_dups,
{
int opn = recog_data.dup_num[i];
old_dups[i] = *recog_data.dup_loc[i];
if (do_not_hide & (1 << opn))
continue;
if (!inout_and_ec_only || recog_data.operand_type[opn] == OP_INOUT
|| recog_op_alt[opn][alt].earlyclobber)
*recog_data.dup_loc[i] = cc0_rtx;
@ -1018,6 +1043,7 @@ build_def_use (basic_block bb)
{
rtx insn;
df_ref *def_rec;
unsigned HOST_WIDE_INT untracked_operands;
open_chains = closed_chains = NULL;
@ -1077,6 +1103,7 @@ build_def_use (basic_block bb)
preprocess_constraints ();
alt = which_alternative;
n_ops = recog_data.n_operands;
untracked_operands = 0;
/* Simplify the code below by rewriting things to reflect
matching constraints. Also promote OP_OUT to OP_INOUT in
@ -1094,11 +1121,21 @@ build_def_use (basic_block bb)
|| (predicated && recog_data.operand_type[i] == OP_OUT
&& verify_reg_tracked (recog_data.operand[i])))
{
rtx op = recog_data.operand[i];
recog_data.operand_type[i] = OP_INOUT;
/* A special case to deal with instruction patterns that
have matching operands with different modes. If we're
not already tracking such a reg, we won't start here,
and we must instead make sure to make the operand visible
to the machinery that tracks hard registers. */
if (matches >= 0
&& (GET_MODE_SIZE (recog_data.operand_mode[i])
!= GET_MODE_SIZE (recog_data.operand_mode[matches])))
fail_current_block = true;
!= GET_MODE_SIZE (recog_data.operand_mode[matches]))
&& !verify_reg_in_set (op, &live_in_chains))
{
untracked_operands |= 1 << i;
untracked_operands |= 1 << matches;
}
}
}
@ -1107,7 +1144,8 @@ build_def_use (basic_block bb)
/* Step 1a: Mark hard registers that are clobbered in this insn,
outside an operand, as live. */
hide_operands (n_ops, old_operands, old_dups, false);
hide_operands (n_ops, old_operands, old_dups, untracked_operands,
false);
note_stores (PATTERN (insn), note_sets_clobbers, &clobber_code);
restore_operands (insn, n_ops, old_operands, old_dups);
@ -1120,7 +1158,8 @@ build_def_use (basic_block bb)
We do this by munging all operands into CC0, and closing
everything remaining. */
hide_operands (n_ops, old_operands, old_dups, false);
hide_operands (n_ops, old_operands, old_dups, untracked_operands,
false);
scan_rtx (insn, &PATTERN (insn), NO_REGS, mark_all_read, OP_IN);
restore_operands (insn, n_ops, old_operands, old_dups);
@ -1157,7 +1196,8 @@ build_def_use (basic_block bb)
/* Don't scan match_operand here, since we've no reg class
information to pass down. Any operands that we could
substitute in will be represented elsewhere. */
if (recog_data.constraints[opn][0] == '\0')
if (recog_data.constraints[opn][0] == '\0'
|| untracked_operands & (1 << opn))
continue;
if (recog_op_alt[opn][alt].is_address)
@ -1202,13 +1242,15 @@ build_def_use (basic_block bb)
the previous insn at the latest, as such operands cannot
possibly overlap with any input operands. */
hide_operands (n_ops, old_operands, old_dups, true);
hide_operands (n_ops, old_operands, old_dups, untracked_operands,
true);
scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN);
restore_operands (insn, n_ops, old_operands, old_dups);
/* Step 6a: Mark hard registers that are set in this insn,
outside an operand, as live. */
hide_operands (n_ops, old_operands, old_dups, false);
hide_operands (n_ops, old_operands, old_dups, untracked_operands,
false);
note_stores (PATTERN (insn), note_sets_clobbers, &set_code);
restore_operands (insn, n_ops, old_operands, old_dups);