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> 2009-12-10 Richard Guenther <rguenther@suse.de>
PR tree-optimization/42337 PR tree-optimization/42337

View File

@ -40,6 +40,10 @@
#include "tree-pass.h" #include "tree-pass.h"
#include "df.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 /* We keep linked lists of DU_HEAD structures, each of which describes
a chain of occurrences of a reg. */ a chain of occurrences of a reg. */
struct du_head struct du_head
@ -434,21 +438,23 @@ static unsigned current_id;
static struct du_head *open_chains; static struct du_head *open_chains;
static struct du_head *closed_chains; static struct du_head *closed_chains;
/* Conflict bitmaps, tracking the live chains and the live hard registers. /* Bitmap of open chains. The bits set always match the list found in
The bits set in open_chains_set always match the list found in
open_chains. */ open_chains. */
static bitmap_head open_chains_set; static bitmap_head open_chains_set;
static HARD_REG_SET live_hard_regs;
/* Record the registers being tracked in open_chains. The intersection /* Record the registers being tracked in open_chains. */
between this and live_hard_regs is empty. */
static HARD_REG_SET live_in_chains; static HARD_REG_SET live_in_chains;
/* Return true if OP is a reg that is being tracked already in some form. /* Record the registers that are live but not tracked. The intersection
May set fail_current_block if it sees an unhandled case of overlap. */ 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 static bool
verify_reg_tracked (rtx op) verify_reg_in_set (rtx op, HARD_REG_SET *pset)
{ {
unsigned regno, nregs; unsigned regno, nregs;
bool all_live, all_dead; bool all_live, all_dead;
@ -459,7 +465,7 @@ verify_reg_tracked (rtx op)
nregs = hard_regno_nregs[regno][GET_MODE (op)]; nregs = hard_regno_nregs[regno][GET_MODE (op)];
all_live = all_dead = true; all_live = all_dead = true;
while (nregs-- > 0) while (nregs-- > 0)
if (TEST_HARD_REG_BIT (live_hard_regs, regno + nregs)) if (TEST_HARD_REG_BIT (*pset, regno + nregs))
all_dead = false; all_dead = false;
else else
all_live = false; all_live = false;
@ -468,26 +474,19 @@ verify_reg_tracked (rtx op)
fail_current_block = true; fail_current_block = true;
return false; 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 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 /* 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 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 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); && head->nregs == this_nregs);
int superset = (this_regno <= head->regno int superset = (this_regno <= head->regno
&& this_regno + this_nregs >= head->regno + head->nregs); && 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 if (head->terminated
|| head->regno + head->nregs <= this_regno || 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), reg_names[head->regno], head->id, INSN_UID (insn),
scan_actions_name[(int) action]); scan_actions_name[(int) action]);
head->cannot_rename = 1; 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 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 /* Hide operands of the current insn (of which there are N_OPS) by
substituting cc0 for them. substituting cc0 for them.
Previous values are stored in the OLD_OPERANDS and OLD_DUPS. 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 If INOUT_AND_EC_ONLY is set, we only do this for OP_INOUT type operands
and earlyclobbers. */ and earlyclobbers. */
static void static void
hide_operands (int n_ops, rtx *old_operands, rtx *old_dups, 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 i;
int alt = which_alternative; int alt = which_alternative;
@ -936,6 +957,8 @@ hide_operands (int n_ops, rtx *old_operands, rtx *old_dups,
reachable by proper operands. */ reachable by proper operands. */
if (recog_data.constraints[i][0] == '\0') if (recog_data.constraints[i][0] == '\0')
continue; continue;
if (do_not_hide & (1 << i))
continue;
if (!inout_and_ec_only || recog_data.operand_type[i] == OP_INOUT if (!inout_and_ec_only || recog_data.operand_type[i] == OP_INOUT
|| recog_op_alt[i][alt].earlyclobber) || recog_op_alt[i][alt].earlyclobber)
*recog_data.operand_loc[i] = cc0_rtx; *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]; int opn = recog_data.dup_num[i];
old_dups[i] = *recog_data.dup_loc[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 if (!inout_and_ec_only || recog_data.operand_type[opn] == OP_INOUT
|| recog_op_alt[opn][alt].earlyclobber) || recog_op_alt[opn][alt].earlyclobber)
*recog_data.dup_loc[i] = cc0_rtx; *recog_data.dup_loc[i] = cc0_rtx;
@ -1018,6 +1043,7 @@ build_def_use (basic_block bb)
{ {
rtx insn; rtx insn;
df_ref *def_rec; df_ref *def_rec;
unsigned HOST_WIDE_INT untracked_operands;
open_chains = closed_chains = NULL; open_chains = closed_chains = NULL;
@ -1077,6 +1103,7 @@ build_def_use (basic_block bb)
preprocess_constraints (); preprocess_constraints ();
alt = which_alternative; alt = which_alternative;
n_ops = recog_data.n_operands; n_ops = recog_data.n_operands;
untracked_operands = 0;
/* Simplify the code below by rewriting things to reflect /* Simplify the code below by rewriting things to reflect
matching constraints. Also promote OP_OUT to OP_INOUT in 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 || (predicated && recog_data.operand_type[i] == OP_OUT
&& verify_reg_tracked (recog_data.operand[i]))) && verify_reg_tracked (recog_data.operand[i])))
{ {
rtx op = recog_data.operand[i];
recog_data.operand_type[i] = OP_INOUT; 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 if (matches >= 0
&& (GET_MODE_SIZE (recog_data.operand_mode[i]) && (GET_MODE_SIZE (recog_data.operand_mode[i])
!= GET_MODE_SIZE (recog_data.operand_mode[matches]))) != GET_MODE_SIZE (recog_data.operand_mode[matches]))
fail_current_block = true; && !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, /* Step 1a: Mark hard registers that are clobbered in this insn,
outside an operand, as live. */ 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); note_stores (PATTERN (insn), note_sets_clobbers, &clobber_code);
restore_operands (insn, n_ops, old_operands, old_dups); 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 We do this by munging all operands into CC0, and closing
everything remaining. */ 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); scan_rtx (insn, &PATTERN (insn), NO_REGS, mark_all_read, OP_IN);
restore_operands (insn, n_ops, old_operands, old_dups); 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 /* Don't scan match_operand here, since we've no reg class
information to pass down. Any operands that we could information to pass down. Any operands that we could
substitute in will be represented elsewhere. */ 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; continue;
if (recog_op_alt[opn][alt].is_address) 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 the previous insn at the latest, as such operands cannot
possibly overlap with any input operands. */ 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); scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN);
restore_operands (insn, n_ops, old_operands, old_dups); restore_operands (insn, n_ops, old_operands, old_dups);
/* Step 6a: Mark hard registers that are set in this insn, /* Step 6a: Mark hard registers that are set in this insn,
outside an operand, as live. */ 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); note_stores (PATTERN (insn), note_sets_clobbers, &set_code);
restore_operands (insn, n_ops, old_operands, old_dups); restore_operands (insn, n_ops, old_operands, old_dups);