aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorBernd Schmidt <bernd.schmidt@analog.com>2009-12-10 18:03:05 +0000
committerBernd Schmidt <bernds@gcc.gnu.org>2009-12-10 18:03:05 +0000
commitd435810e760bccf8d45f440d7fe85068fb621a2e (patch)
tree3b8366558ed3afbd3865c46fc4d7d6f3644d04eb /gcc
parent574f366488bbe1bf3075735278242a92be85f40b (diff)
downloadgcc-d435810e760bccf8d45f440d7fe85068fb621a2e.zip
gcc-d435810e760bccf8d45f440d7fe85068fb621a2e.tar.gz
gcc-d435810e760bccf8d45f440d7fe85068fb621a2e.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/regrename.c108
2 files changed, 94 insertions, 33 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b90eb2b..2e53db2 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/regrename.c b/gcc/regrename.c
index 0026324..e003fd4 100644
--- a/gcc/regrename.c
+++ b/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,24 +474,17 @@ verify_reg_tracked (rtx op)
fail_current_block = true;
return false;
}
+ return all_live;
+}
- 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 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. */
- return all_live;
+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
@@ -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);