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:
parent
39b75e51ec
commit
d3e8085069
2 changed files with 210 additions and 203 deletions
|
@ -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.
|
||||
|
|
398
gcc/regrename.c
398
gcc/regrename.c
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue