From c38fa63b5f3c4e2f37f762e1ec5a9d2c3486dc8b Mon Sep 17 00:00:00 2001 From: bernds Date: Thu, 10 Dec 2009 18:03:05 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@155134 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 19 ++++++++++ gcc/regrename.c | 108 +++++++++++++++++++++++++++++++++++++++----------------- 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 + + 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 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); -- 2.7.4