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:
parent
c5c39ab37a
commit
6bda9bdf52
@ -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.
|
||||
|
234
gcc/regrename.c
234
gcc/regrename.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user