re PR rtl-optimization/38582 (excessive time in rename registers)

PR rtl-opt/38582
	* regrename.c (struct du_chain): Remove member earlyclobber.
	(scan_rtx_reg): Don't set it.  Remove argument earlyclobber,
	all callers changed.
	(scan_rtx): Remove argument earlyclobber, all callers changed.
	(hide_operands, restore_operands, record_out_operands): New functions,
	broken out of build_def_use.
	(build_def_use): Call them as necessary.

From-SVN: r154687
This commit is contained in:
Bernd Schmidt 2009-11-26 21:35:35 +00:00 committed by Bernd Schmidt
parent c5c39ab37a
commit 6bda9bdf52
2 changed files with 135 additions and 110 deletions

View File

@ -1,3 +1,14 @@
2009-11-26 Bernd Schmidt <bernd.schmidt@analog.com>
PR rtl-opt/38582
* regrename.c (struct du_chain): Remove member earlyclobber.
(scan_rtx_reg): Don't set it. Remove argument earlyclobber,
all callers changed.
(scan_rtx): Remove argument earlyclobber, all callers changed.
(hide_operands, restore_operands, record_out_operands): New functions,
broken out of build_def_use.
(build_def_use): Call them as necessary.
2009-11-26 Richard Guenther <rguenther@suse.de>
* tree-ssa-dce.c (nr_walks): New variable.

View File

@ -68,8 +68,6 @@ struct du_chain
rtx *loc;
/* The register class required by the insn at this location. */
ENUM_BITFIELD(reg_class) cl : 16;
/* Nonzero if the register is subject to earlyclobber. */
unsigned int earlyclobber:1;
};
enum scan_actions
@ -101,11 +99,11 @@ static struct obstack rename_obstack;
static void do_replace (struct du_head *, int);
static void scan_rtx_reg (rtx, rtx *, enum reg_class,
enum scan_actions, enum op_type, int);
enum scan_actions, enum op_type);
static void scan_rtx_address (rtx, rtx *, enum reg_class,
enum scan_actions, enum machine_mode);
static void scan_rtx (rtx, rtx *, enum reg_class, enum scan_actions,
enum op_type, int);
enum op_type);
static struct du_head *build_def_use (basic_block);
static void dump_def_use_chain (struct du_head *);
static void note_sets (rtx, const_rtx, void *);
@ -431,8 +429,8 @@ static struct du_head *open_chains;
static struct du_head *closed_chains;
static void
scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl,
enum scan_actions action, enum op_type type, int earlyclobber)
scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
enum op_type type)
{
struct du_head **p;
rtx x = *loc;
@ -458,7 +456,6 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl,
this_du->loc = loc;
this_du->insn = insn;
this_du->cl = cl;
this_du->earlyclobber = earlyclobber;
}
return;
}
@ -681,7 +678,7 @@ scan_rtx_address (rtx insn, rtx *loc, enum reg_class cl,
return;
case REG:
scan_rtx_reg (insn, loc, cl, action, OP_IN, 0);
scan_rtx_reg (insn, loc, cl, action, OP_IN);
return;
default:
@ -700,8 +697,8 @@ scan_rtx_address (rtx insn, rtx *loc, enum reg_class cl,
}
static void
scan_rtx (rtx insn, rtx *loc, enum reg_class cl,
enum scan_actions action, enum op_type type, int earlyclobber)
scan_rtx (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
enum op_type type)
{
const char *fmt;
rtx x = *loc;
@ -723,7 +720,7 @@ scan_rtx (rtx insn, rtx *loc, enum reg_class cl,
return;
case REG:
scan_rtx_reg (insn, loc, cl, action, type, earlyclobber);
scan_rtx_reg (insn, loc, cl, action, type);
return;
case MEM:
@ -733,21 +730,21 @@ scan_rtx (rtx insn, rtx *loc, enum reg_class cl,
return;
case SET:
scan_rtx (insn, &SET_SRC (x), cl, action, OP_IN, 0);
scan_rtx (insn, &SET_SRC (x), cl, action, OP_IN);
scan_rtx (insn, &SET_DEST (x), cl, action,
GET_CODE (PATTERN (insn)) == COND_EXEC ? OP_INOUT : OP_OUT, 0);
GET_CODE (PATTERN (insn)) == COND_EXEC ? OP_INOUT : OP_OUT);
return;
case STRICT_LOW_PART:
scan_rtx (insn, &XEXP (x, 0), cl, action, OP_INOUT, earlyclobber);
scan_rtx (insn, &XEXP (x, 0), cl, action, OP_INOUT);
return;
case ZERO_EXTRACT:
case SIGN_EXTRACT:
scan_rtx (insn, &XEXP (x, 0), cl, action,
type == OP_IN ? OP_IN : OP_INOUT, earlyclobber);
scan_rtx (insn, &XEXP (x, 1), cl, action, OP_IN, 0);
scan_rtx (insn, &XEXP (x, 2), cl, action, OP_IN, 0);
type == OP_IN ? OP_IN : OP_INOUT);
scan_rtx (insn, &XEXP (x, 1), cl, action, OP_IN);
scan_rtx (insn, &XEXP (x, 2), cl, action, OP_IN);
return;
case POST_INC:
@ -761,13 +758,13 @@ scan_rtx (rtx insn, rtx *loc, enum reg_class cl,
case CLOBBER:
scan_rtx (insn, &SET_DEST (x), cl, action,
GET_CODE (PATTERN (insn)) == COND_EXEC ? OP_INOUT : OP_OUT, 0);
GET_CODE (PATTERN (insn)) == COND_EXEC ? OP_INOUT : OP_OUT);
return;
case EXPR_LIST:
scan_rtx (insn, &XEXP (x, 0), cl, action, type, 0);
scan_rtx (insn, &XEXP (x, 0), cl, action, type);
if (XEXP (x, 1))
scan_rtx (insn, &XEXP (x, 1), cl, action, type, 0);
scan_rtx (insn, &XEXP (x, 1), cl, action, type);
return;
default:
@ -778,10 +775,99 @@ scan_rtx (rtx insn, rtx *loc, enum reg_class cl,
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
scan_rtx (insn, &XEXP (x, i), cl, action, type, 0);
scan_rtx (insn, &XEXP (x, i), cl, action, type);
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
scan_rtx (insn, &XVECEXP (x, i, j), cl, action, type, 0);
scan_rtx (insn, &XVECEXP (x, i, j), cl, action, type);
}
}
/* 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.
If INOUT_ONLY is set, we only do this for OP_INOUT type operands. */
static void
hide_operands (int n_ops, rtx *old_operands, rtx *old_dups,
bool inout_only)
{
int i;
for (i = 0; i < n_ops; i++)
{
old_operands[i] = recog_data.operand[i];
/* Don't squash match_operator or match_parallel here, since
we don't know that all of the contained registers are
reachable by proper operands. */
if (recog_data.constraints[i][0] == '\0')
continue;
if (!inout_only || recog_data.operand_type[i] == OP_INOUT)
*recog_data.operand_loc[i] = cc0_rtx;
}
for (i = 0; i < recog_data.n_dups; i++)
{
int opn = recog_data.dup_num[i];
old_dups[i] = *recog_data.dup_loc[i];
if (!inout_only || recog_data.operand_type[opn] == OP_INOUT)
*recog_data.dup_loc[i] = cc0_rtx;
}
}
/* Undo the substitution performed by hide_operands. INSN is the insn we
are processing; the arguments are the same as in hide_operands. */
static void
restore_operands (rtx insn, int n_ops, rtx *old_operands, rtx *old_dups)
{
int i;
for (i = 0; i < recog_data.n_dups; i++)
*recog_data.dup_loc[i] = old_dups[i];
for (i = 0; i < n_ops; i++)
*recog_data.operand_loc[i] = old_operands[i];
if (recog_data.n_dups)
df_insn_rescan (insn);
}
/* For each output operand of INSN, call scan_rtx to create a new
open chain. */
static void
record_out_operands (rtx insn)
{
int n_ops = recog_data.n_operands;
int alt = which_alternative;
int i;
for (i = 0; i < n_ops + recog_data.n_dups; i++)
{
int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops];
rtx *loc = (i < n_ops
? recog_data.operand_loc[opn]
: recog_data.dup_loc[i - n_ops]);
rtx op = *loc;
enum reg_class cl = recog_op_alt[opn][alt].cl;
struct du_head *prev_open;
if (recog_data.operand_type[opn] != OP_OUT)
continue;
prev_open = open_chains;
scan_rtx (insn, loc, cl, mark_write, OP_OUT);
/* ??? Many targets have output constraints on the SET_DEST
of a call insn, which is stupid, since these are certainly
ABI defined hard registers. For these, and for asm operands
that originally referenced hard registers, we must record that
the chain cannot be renamed. */
if (CALL_P (insn)
|| (asm_noperands (PATTERN (insn)) > 0
&& REG_P (op)
&& REGNO (op) == ORIGINAL_REGNO (op)))
{
if (prev_open != open_chains)
open_chains->first->cl = NO_REGS;
}
}
}
@ -849,42 +935,21 @@ build_def_use (basic_block bb)
for (i = 0; i < n_ops; i++)
scan_rtx (insn, recog_data.operand_loc[i],
NO_REGS, terminate_overlapping_read,
recog_data.operand_type[i], 0);
recog_data.operand_type[i]);
/* Step 2: Close chains for which we have reads outside operands.
We do this by munging all operands into CC0, and closing
everything remaining. */
for (i = 0; i < n_ops; i++)
{
old_operands[i] = recog_data.operand[i];
/* Don't squash match_operator or match_parallel here, since
we don't know that all of the contained registers are
reachable by proper operands. */
if (recog_data.constraints[i][0] == '\0')
continue;
*recog_data.operand_loc[i] = cc0_rtx;
}
for (i = 0; i < recog_data.n_dups; i++)
{
old_dups[i] = *recog_data.dup_loc[i];
*recog_data.dup_loc[i] = cc0_rtx;
}
hide_operands (n_ops, old_operands, old_dups, false);
scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_all_read,
OP_IN, 0);
for (i = 0; i < recog_data.n_dups; i++)
*recog_data.dup_loc[i] = old_dups[i];
for (i = 0; i < n_ops; i++)
*recog_data.operand_loc[i] = old_operands[i];
if (recog_data.n_dups)
df_insn_rescan (insn);
OP_IN);
restore_operands (insn, n_ops, old_operands, old_dups);
/* Step 2B: Can't rename function call argument registers. */
if (CALL_P (insn) && CALL_INSN_FUNCTION_USAGE (insn))
scan_rtx (insn, &CALL_INSN_FUNCTION_USAGE (insn),
NO_REGS, terminate_all_read, OP_IN, 0);
NO_REGS, terminate_all_read, OP_IN);
/* Step 2C: Can't rename asm operands that were originally
hard registers. */
@ -898,7 +963,7 @@ build_def_use (basic_block bb)
&& REGNO (op) == ORIGINAL_REGNO (op)
&& (recog_data.operand_type[i] == OP_IN
|| recog_data.operand_type[i] == OP_INOUT))
scan_rtx (insn, loc, NO_REGS, terminate_all_read, OP_IN, 0);
scan_rtx (insn, loc, NO_REGS, terminate_all_read, OP_IN);
}
/* Step 3: Append to chains for reads inside operands. */
@ -920,7 +985,7 @@ build_def_use (basic_block bb)
if (recog_op_alt[opn][alt].is_address)
scan_rtx_address (insn, loc, cl, mark_read, VOIDmode);
else
scan_rtx (insn, loc, cl, mark_read, type, 0);
scan_rtx (insn, loc, cl, mark_read, type);
}
/* Step 3B: Record updates for regs in REG_INC notes, and
@ -929,13 +994,13 @@ build_def_use (basic_block bb)
if (REG_NOTE_KIND (note) == REG_INC
|| REG_NOTE_KIND (note) == REG_FRAME_RELATED_EXPR)
scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_read,
OP_INOUT, 0);
OP_INOUT);
/* Step 4: Close chains for registers that die here. */
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_DEAD)
scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead,
OP_IN, 0);
OP_IN);
/* Step 4B: If this is a call, any chain live at this point
requires a caller-saved reg. */
@ -950,83 +1015,32 @@ build_def_use (basic_block bb)
step 2, we hide in-out operands, since we do not want to
close these chains. */
for (i = 0; i < n_ops; i++)
{
old_operands[i] = recog_data.operand[i];
if (recog_data.operand_type[i] == OP_INOUT)
*recog_data.operand_loc[i] = cc0_rtx;
}
for (i = 0; i < recog_data.n_dups; i++)
{
int opn = recog_data.dup_num[i];
old_dups[i] = *recog_data.dup_loc[i];
if (recog_data.operand_type[opn] == OP_INOUT)
*recog_data.dup_loc[i] = cc0_rtx;
}
scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN, 0);
for (i = 0; i < recog_data.n_dups; i++)
*recog_data.dup_loc[i] = old_dups[i];
for (i = 0; i < n_ops; i++)
*recog_data.operand_loc[i] = old_operands[i];
hide_operands (n_ops, old_operands, old_dups, true);
scan_rtx (insn, &PATTERN (insn), NO_REGS, terminate_write, OP_IN);
restore_operands (insn, n_ops, old_operands, old_dups);
/* Step 6: Begin new chains for writes inside operands. */
/* ??? Many targets have output constraints on the SET_DEST
of a call insn, which is stupid, since these are certainly
ABI defined hard registers. Don't change calls at all.
Similarly take special care for asm statement that originally
referenced hard registers. */
if (asm_noperands (PATTERN (insn)) > 0)
{
for (i = 0; i < n_ops; i++)
if (recog_data.operand_type[i] == OP_OUT)
{
rtx *loc = recog_data.operand_loc[i];
rtx op = *loc;
enum reg_class cl = recog_op_alt[i][alt].cl;
if (REG_P (op)
&& REGNO (op) == ORIGINAL_REGNO (op))
continue;
scan_rtx (insn, loc, cl, mark_write, OP_OUT,
recog_op_alt[i][alt].earlyclobber);
}
}
else if (!CALL_P (insn))
for (i = 0; i < n_ops + recog_data.n_dups; i++)
{
int opn = i < n_ops ? i : recog_data.dup_num[i - n_ops];
rtx *loc = (i < n_ops
? recog_data.operand_loc[opn]
: recog_data.dup_loc[i - n_ops]);
enum reg_class cl = recog_op_alt[opn][alt].cl;
if (recog_data.operand_type[opn] == OP_OUT)
scan_rtx (insn, loc, cl, mark_write, OP_OUT,
recog_op_alt[opn][alt].earlyclobber);
}
record_out_operands (insn);
/* Step 6B: Record destination regs in REG_FRAME_RELATED_EXPR
notes for update. */
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_FRAME_RELATED_EXPR)
scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_access,
OP_INOUT, 0);
OP_INOUT);
/* Step 7: Close chains for registers that were never
really used here. */
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_UNUSED)
scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead,
OP_IN, 0);
OP_IN);
}
else if (DEBUG_INSN_P (insn)
&& !VAR_LOC_UNKNOWN_P (INSN_VAR_LOCATION_LOC (insn)))
{
scan_rtx (insn, &INSN_VAR_LOCATION_LOC (insn),
ALL_REGS, mark_read, OP_IN, 0);
ALL_REGS, mark_read, OP_IN);
}
if (insn == BB_END (bb))
break;