===================================================================
@@ -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_n
"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 d
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,160 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSE
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 +439,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 +450,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);
@@ -507,24 +544,6 @@ mark_conflict (struct du_head *chains, u
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. */
@@ -603,7 +622,6 @@ create_new_chain (unsigned this_regno, u
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++;
@@ -682,7 +700,7 @@ scan_rtx_reg (rtx insn, rtx *loc, enum r
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)
{
@@ -757,7 +775,6 @@ scan_rtx_reg (rtx insn, rtx *loc, enum r
{
unsigned nregs;
- head->terminated = 1;
head->next_chain = closed_chains;
closed_chains = head;
bitmap_clear_bit (&open_chains_set, head->id);
@@ -1407,29 +1424,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)