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:
parent
574f366488
commit
d435810e76
|
@ -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
|
||||
|
|
110
gcc/regrename.c
110
gcc/regrename.c
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue