regrename.c (struct du_head): Remove member terminated.

* regrename.c (struct du_head): Remove member terminated.
	(create_new_chain): Don't initialize it.
	(scan_rtx_reg): Don't set or test it, test the open_chains_set
	bitmap instead.
	(tick, this_tick): New global variables, moved out of
	regrename_optimize.
	(current_id, open_chains, closed_chains, open_chains_set,
	live_in_chains, live_hard_regs): Reorder declarations.
	(dump_def_use_chain): Move function earlier in the file.
	(rename_chains): New static function, broken out of
	regrename_optimize.
	(regrename_optimize): Use it.  Remove #if 0'ed code.

From-SVN: r178057
This commit is contained in:
Bernd Schmidt 2011-08-25 10:12:35 +00:00 committed by Bernd Schmidt
parent 39b75e51ec
commit d3e8085069
2 changed files with 210 additions and 203 deletions

View file

@ -1,3 +1,18 @@
2011-08-25 Bernd Schmidt <bernds@codesourcery.com>
* regrename.c (struct du_head): Remove member terminated.
(create_new_chain): Don't initialize it.
(scan_rtx_reg): Don't set or test it, test the open_chains_set
bitmap instead.
(tick, this_tick): New global variables, moved out of
regrename_optimize.
(current_id, open_chains, closed_chains, open_chains_set,
live_in_chains, live_hard_regs): Reorder declarations.
(dump_def_use_chain): Move function earlier in the file.
(rename_chains): New static function, broken out of
regrename_optimize.
(regrename_optimize): Use it. Remove #if 0'ed code.
2011-08-25 Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
* varasm.c: (default_binds_local_p_1): Commentary typo fix.

View file

@ -85,8 +85,6 @@ struct du_head
/* Conflicts with untracked hard registers. */
HARD_REG_SET hard_conflicts;
/* Nonzero if the chain is finished; zero if it is still open. */
unsigned int terminated:1;
/* Nonzero if the chain crosses a call. */
unsigned int need_caller_save_reg:1;
/* Nonzero if the register is used in a way that prevents renaming,
@ -132,6 +130,11 @@ static const char * const scan_actions_name[] =
"mark_access"
};
/* TICK and THIS_TICK are used to record the last time we saw each
register. */
static int tick[FIRST_PSEUDO_REGISTER];
static int this_tick = 0;
static struct obstack rename_obstack;
static void do_replace (struct du_head *, int);
@ -147,8 +150,49 @@ static void dump_def_use_chain (struct du_head *);
typedef struct du_head *du_head_p;
DEF_VEC_P (du_head_p);
DEF_VEC_ALLOC_P (du_head_p, heap);
/* The id to be given to the next opened chain. */
static unsigned current_id;
/* A mapping of unique id numbers to chains. */
static VEC(du_head_p, heap) *id_to_chain;
/* List of currently open chains, and closed chains that can be renamed. */
static struct du_head *open_chains;
static struct du_head *closed_chains;
/* Bitmap of open chains. The bits set always match the list found in
open_chains. */
static bitmap_head open_chains_set;
/* Record the registers being tracked in open_chains. */
static HARD_REG_SET live_in_chains;
/* 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;
/* Dump all def/use chains in CHAINS to DUMP_FILE. */
static void
dump_def_use_chain (struct du_head *head)
{
while (head)
{
struct du_chain *this_du = head->first;
fprintf (dump_file, "Register %s (%d):",
reg_names[head->regno], head->nregs);
while (this_du)
{
fprintf (dump_file, " %d [%s]", INSN_UID (this_du->insn),
reg_class_names[this_du->cl]);
this_du = this_du->next_use;
}
fprintf (dump_file, "\n");
head = head->next_chain;
}
}
static void
free_chain_data (void)
{
@ -225,13 +269,158 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg,
return true;
}
/* Process the closed chains starting with ALL_CHAINS and rename
registers if possible. */
static void
rename_chains (du_head_p all_chains)
{
HARD_REG_SET unavailable;
CLEAR_HARD_REG_SET (unavailable);
/* Don't clobber traceback for noreturn functions. */
if (frame_pointer_needed)
{
add_to_hard_reg_set (&unavailable, Pmode, FRAME_POINTER_REGNUM);
#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
add_to_hard_reg_set (&unavailable, Pmode, HARD_FRAME_POINTER_REGNUM);
#endif
}
while (all_chains)
{
int new_reg, best_new_reg, best_nregs;
int n_uses;
struct du_head *this_head = all_chains;
struct du_chain *tmp;
HARD_REG_SET this_unavailable;
int reg = this_head->regno;
int pass;
enum reg_class super_class = NO_REGS;
enum reg_class preferred_class;
bool has_preferred_class;
all_chains = this_head->next_chain;
if (this_head->cannot_rename)
continue;
best_new_reg = reg;
best_nregs = this_head->nregs;
if (fixed_regs[reg] || global_regs[reg]
#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
|| (frame_pointer_needed && reg == HARD_FRAME_POINTER_REGNUM)
#else
|| (frame_pointer_needed && reg == FRAME_POINTER_REGNUM)
#endif
)
continue;
COPY_HARD_REG_SET (this_unavailable, unavailable);
/* Iterate over elements in the chain in order to:
1. Count number of uses, and narrow the set of registers we can
use for renaming.
2. Compute the superunion of register classes in this chain. */
n_uses = 0;
super_class = NO_REGS;
for (tmp = this_head->first; tmp; tmp = tmp->next_use)
{
if (DEBUG_INSN_P (tmp->insn))
continue;
n_uses++;
IOR_COMPL_HARD_REG_SET (this_unavailable,
reg_class_contents[tmp->cl]);
super_class
= reg_class_superunion[(int) super_class][(int) tmp->cl];
}
if (n_uses < 2)
continue;
/* Further narrow the set of registers we can use for renaming.
If the chain needs a call-saved register, mark the call-used
registers as unavailable. */
if (this_head->need_caller_save_reg)
IOR_HARD_REG_SET (this_unavailable, call_used_reg_set);
/* And mark registers that overlap its lifetime as unavailable. */
merge_overlapping_regs (&this_unavailable, this_head);
/* Compute preferred rename class of super union of all the classes
in the chain. */
preferred_class
= (enum reg_class) targetm.preferred_rename_class (super_class);
/* If PREFERRED_CLASS is not NO_REGS, we iterate in the first pass
over registers that belong to PREFERRED_CLASS and try to find the
best register within the class. If that failed, we iterate in
the second pass over registers that don't belong to the class.
If PREFERRED_CLASS is NO_REGS, we iterate over all registers in
ascending order without any preference. */
has_preferred_class = (preferred_class != NO_REGS);
for (pass = (has_preferred_class ? 0 : 1); pass < 2; pass++)
{
for (new_reg = 0; new_reg < FIRST_PSEUDO_REGISTER; new_reg++)
{
if (has_preferred_class
&& ((pass == 0) != TEST_HARD_REG_BIT
(reg_class_contents[preferred_class], new_reg)))
continue;
/* In the first pass, we force the renaming of registers that
don't belong to PREFERRED_CLASS to registers that do, even
though the latters were used not very long ago. */
if (check_new_reg_p (reg, new_reg, this_head,
this_unavailable)
&& ((pass == 0
&& (!TEST_HARD_REG_BIT
(reg_class_contents[preferred_class],
best_new_reg)))
|| tick[best_new_reg] > tick[new_reg]))
{
enum machine_mode mode
= GET_MODE (*this_head->first->loc);
best_new_reg = new_reg;
best_nregs = hard_regno_nregs[new_reg][mode];
}
}
if (pass == 0 && best_new_reg != reg)
break;
}
if (dump_file)
{
fprintf (dump_file, "Register %s in insn %d",
reg_names[reg], INSN_UID (this_head->first->insn));
if (this_head->need_caller_save_reg)
fprintf (dump_file, " crosses a call");
}
if (best_new_reg == reg)
{
tick[reg] = ++this_tick;
if (dump_file)
fprintf (dump_file, "; no available better choice\n");
continue;
}
if (dump_file)
fprintf (dump_file, ", renamed as %s\n", reg_names[best_new_reg]);
do_replace (this_head, best_new_reg);
this_head->regno = best_new_reg;
this_head->nregs = best_nregs;
tick[best_new_reg] = ++this_tick;
df_set_regs_ever_live (best_new_reg, true);
}
}
/* Perform register renaming on the current function. */
static unsigned int
regrename_optimize (void)
{
int tick[FIRST_PSEUDO_REGISTER];
int this_tick = 0;
basic_block bb;
char *first_obj;
@ -248,16 +437,9 @@ regrename_optimize (void)
FOR_EACH_BB (bb)
{
struct du_head *all_chains = 0;
HARD_REG_SET unavailable;
#if 0
HARD_REG_SET regs_seen;
CLEAR_HARD_REG_SET (regs_seen);
#endif
id_to_chain = VEC_alloc (du_head_p, heap, 0);
CLEAR_HARD_REG_SET (unavailable);
if (dump_file)
fprintf (dump_file, "\nBasic block %d:\n", bb->index);
@ -266,154 +448,7 @@ regrename_optimize (void)
if (dump_file)
dump_def_use_chain (all_chains);
CLEAR_HARD_REG_SET (unavailable);
/* Don't clobber traceback for noreturn functions. */
if (frame_pointer_needed)
{
add_to_hard_reg_set (&unavailable, Pmode, FRAME_POINTER_REGNUM);
#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
add_to_hard_reg_set (&unavailable, Pmode, HARD_FRAME_POINTER_REGNUM);
#endif
}
while (all_chains)
{
int new_reg, best_new_reg, best_nregs;
int n_uses;
struct du_head *this_head = all_chains;
struct du_chain *tmp;
HARD_REG_SET this_unavailable;
int reg = this_head->regno;
int pass;
enum reg_class super_class = NO_REGS;
enum reg_class preferred_class;
bool has_preferred_class;
all_chains = this_head->next_chain;
if (this_head->cannot_rename)
continue;
best_new_reg = reg;
best_nregs = this_head->nregs;
#if 0 /* This just disables optimization opportunities. */
/* Only rename once we've seen the reg more than once. */
if (! TEST_HARD_REG_BIT (regs_seen, reg))
{
SET_HARD_REG_BIT (regs_seen, reg);
continue;
}
#endif
if (fixed_regs[reg] || global_regs[reg]
#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
|| (frame_pointer_needed && reg == HARD_FRAME_POINTER_REGNUM)
#else
|| (frame_pointer_needed && reg == FRAME_POINTER_REGNUM)
#endif
)
continue;
COPY_HARD_REG_SET (this_unavailable, unavailable);
/* Iterate over elements in the chain in order to:
1. Count number of uses, and narrow the set of registers we can
use for renaming.
2. Compute the superunion of register classes in this chain. */
n_uses = 0;
super_class = NO_REGS;
for (tmp = this_head->first; tmp; tmp = tmp->next_use)
{
if (DEBUG_INSN_P (tmp->insn))
continue;
n_uses++;
IOR_COMPL_HARD_REG_SET (this_unavailable,
reg_class_contents[tmp->cl]);
super_class
= reg_class_superunion[(int) super_class][(int) tmp->cl];
}
if (n_uses < 2)
continue;
/* Further narrow the set of registers we can use for renaming.
If the chain needs a call-saved register, mark the call-used
registers as unavailable. */
if (this_head->need_caller_save_reg)
IOR_HARD_REG_SET (this_unavailable, call_used_reg_set);
/* And mark registers that overlap its lifetime as unavailable. */
merge_overlapping_regs (&this_unavailable, this_head);
/* Compute preferred rename class of super union of all the classes
in the chain. */
preferred_class
= (enum reg_class) targetm.preferred_rename_class (super_class);
/* If PREFERRED_CLASS is not NO_REGS, we iterate in the first pass
over registers that belong to PREFERRED_CLASS and try to find the
best register within the class. If that failed, we iterate in
the second pass over registers that don't belong to the class.
If PREFERRED_CLASS is NO_REGS, we iterate over all registers in
ascending order without any preference. */
has_preferred_class = (preferred_class != NO_REGS);
for (pass = (has_preferred_class ? 0 : 1); pass < 2; pass++)
{
for (new_reg = 0; new_reg < FIRST_PSEUDO_REGISTER; new_reg++)
{
if (has_preferred_class
&& (pass == 0)
!= TEST_HARD_REG_BIT
(reg_class_contents[preferred_class], new_reg))
continue;
/* In the first pass, we force the renaming of registers that
don't belong to PREFERRED_CLASS to registers that do, even
though the latters were used not very long ago. */
if (check_new_reg_p (reg, new_reg, this_head,
this_unavailable)
&& ((pass == 0
&& !TEST_HARD_REG_BIT
(reg_class_contents[preferred_class],
best_new_reg))
|| tick[best_new_reg] > tick[new_reg]))
{
enum machine_mode mode
= GET_MODE (*this_head->first->loc);
best_new_reg = new_reg;
best_nregs = hard_regno_nregs[new_reg][mode];
}
}
if (pass == 0 && best_new_reg != reg)
break;
}
if (dump_file)
{
fprintf (dump_file, "Register %s in insn %d",
reg_names[reg], INSN_UID (this_head->first->insn));
if (this_head->need_caller_save_reg)
fprintf (dump_file, " crosses a call");
}
if (best_new_reg == reg)
{
tick[reg] = ++this_tick;
if (dump_file)
fprintf (dump_file, "; no available better choice\n");
continue;
}
if (dump_file)
fprintf (dump_file, ", renamed as %s\n", reg_names[best_new_reg]);
do_replace (this_head, best_new_reg);
this_head->regno = best_new_reg;
this_head->nregs = best_nregs;
tick[best_new_reg] = ++this_tick;
df_set_regs_ever_live (best_new_reg, true);
}
rename_chains (all_chains);
free_chain_data ();
obstack_free (&rename_obstack, first_obj);
@ -475,24 +510,6 @@ mark_conflict (struct du_head *chains, unsigned id)
without renaming. */
static bool fail_current_block;
/* The id to be given to the next opened chain. */
static unsigned current_id;
/* List of currently open chains, and closed chains that can be renamed. */
static struct du_head *open_chains;
static struct du_head *closed_chains;
/* Bitmap of open chains. The bits set always match the list found in
open_chains. */
static bitmap_head open_chains_set;
/* Record the registers being tracked in open_chains. */
static HARD_REG_SET live_in_chains;
/* 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. */
@ -571,7 +588,6 @@ create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc,
head->nregs = this_nregs;
head->need_caller_save_reg = 0;
head->cannot_rename = 0;
head->terminated = 0;
VEC_safe_push (du_head_p, heap, id_to_chain, head);
head->id = current_id++;
@ -650,7 +666,7 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
int subset = (this_regno >= head->regno
&& this_regno + this_nregs <= head->regno + head->nregs);
if (head->terminated
if (!bitmap_bit_p (&open_chains_set, head->id)
|| head->regno + head->nregs <= this_regno
|| this_regno + this_nregs <= head->regno)
{
@ -725,7 +741,6 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
{
unsigned nregs;
head->terminated = 1;
if (subset && !superset)
head->cannot_rename = 1;
head->next_chain = closed_chains;
@ -1384,29 +1399,6 @@ build_def_use (basic_block bb)
is still open lives past the basic block, so it can't be renamed. */
return closed_chains;
}
/* Dump all def/use chains in CHAINS to DUMP_FILE. They are
printed in reverse order as that's how we build them. */
static void
dump_def_use_chain (struct du_head *head)
{
while (head)
{
struct du_chain *this_du = head->first;
fprintf (dump_file, "Register %s (%d):",
reg_names[head->regno], head->nregs);
while (this_du)
{
fprintf (dump_file, " %d [%s]", INSN_UID (this_du->insn),
reg_class_names[this_du->cl]);
this_du = this_du->next_use;
}
fprintf (dump_file, "\n");
head = head->next_chain;
}
}
static bool
gate_handle_regrename (void)