Commit 9d324dde by Bernd Schmidt Committed by Bernd Schmidt

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

	PR rtl-opt/38582
	* regrename.c (struct du_head): New structure; some elements moved
	from...
	(struct du_chain): ... this one.
	(open_chains, closed_chains): Now of type struct du_head *.
	(do_replace): Accept du_head argument, not du_chain.  All callers
	changed.  Modified code to match new data structures.
	(build_def_use): Return a list of du_head structures.  Modified code
	to match new data structures.
	(dump_def_use_chain): Accept du_head argument, not du_chain.  All
	callers changed.  Modified code to match new data structures.
	(merge_overlapping_regs): Accept du_head argument, not du_chain.  All
	callers changed.  Modified code to match new data structures.
	(scan_rtx_reg): Change type of this_regno and this_nregs to unsigned.
	Allocate a du_head structure as well as a du_chain when creating a
	new chain.  Modified other code to match new data structures.

From-SVN: r154123
parent a8289259
2009-11-12 Bernd Schmidt <bernd.schmidt@analog.com>
PR rtl-opt/38582
* regrename.c (struct du_head): New structure; some elements moved
from...
(struct du_chain): ... this one.
(open_chains, closed_chains): Now of type struct du_head *.
(do_replace): Accept du_head argument, not du_chain. All callers
changed. Modified code to match new data structures.
(build_def_use): Return a list of du_head structures. Modified code
to match new data structures.
(dump_def_use_chain): Accept du_head argument, not du_chain. All
callers changed. Modified code to match new data structures.
(merge_overlapping_regs): Accept du_head argument, not du_chain. All
callers changed. Modified code to match new data structures.
(scan_rtx_reg): Change type of this_regno and this_nregs to unsigned.
Allocate a du_head structure as well as a du_chain when creating a
new chain. Modified other code to match new data structures.
2009-11-12 Jan Hubicka <jh@suse.cz> 2009-11-12 Jan Hubicka <jh@suse.cz>
* cgraph.h (varpool_node_name): Declare. * cgraph.h (varpool_node_name): Declare.
...@@ -40,15 +40,35 @@ ...@@ -40,15 +40,35 @@
#include "tree-pass.h" #include "tree-pass.h"
#include "df.h" #include "df.h"
/* We keep linked lists of DU_HEAD structures, each of which describes
a chain of occurrences of a reg. */
struct du_head
{
/* The next chain. */
struct du_head *next_chain;
/* The first and last elements of this chain. */
struct du_chain *first, *last;
/* Describes the register being tracked. */
unsigned regno, nregs;
/* Nonzero if the chain crosses a call. */
unsigned int need_caller_save_reg:1;
/* Nonzero if the chain is finished. */
unsigned int terminated:1;
};
/* This struct describes a single occurrence of a register. */
struct du_chain struct du_chain
{ {
struct du_chain *next_chain; /* Links to the next occurrence of the register. */
struct du_chain *next_use; struct du_chain *next_use;
/* The insn where the register appears. */
rtx insn; rtx insn;
/* The location inside the insn. */
rtx *loc; rtx *loc;
/* The register class required by the insn at this location. */
ENUM_BITFIELD(reg_class) cl : 16; ENUM_BITFIELD(reg_class) cl : 16;
unsigned int need_caller_save_reg:1; /* Nonzero if the register is subject to earlyclobber. */
unsigned int earlyclobber:1; unsigned int earlyclobber:1;
}; };
...@@ -79,19 +99,19 @@ static const char * const scan_actions_name[] = ...@@ -79,19 +99,19 @@ static const char * const scan_actions_name[] =
static struct obstack rename_obstack; static struct obstack rename_obstack;
static void do_replace (struct du_chain *, int); static void do_replace (struct du_head *, int);
static void scan_rtx_reg (rtx, rtx *, enum reg_class, static void scan_rtx_reg (rtx, rtx *, enum reg_class,
enum scan_actions, enum op_type, int); enum scan_actions, enum op_type, int);
static void scan_rtx_address (rtx, rtx *, enum reg_class, static void scan_rtx_address (rtx, rtx *, enum reg_class,
enum scan_actions, enum machine_mode); enum scan_actions, enum machine_mode);
static void scan_rtx (rtx, rtx *, enum reg_class, enum scan_actions, static void scan_rtx (rtx, rtx *, enum reg_class, enum scan_actions,
enum op_type, int); enum op_type, int);
static struct du_chain *build_def_use (basic_block); static struct du_head *build_def_use (basic_block);
static void dump_def_use_chain (struct du_chain *); static void dump_def_use_chain (struct du_head *);
static void note_sets (rtx, const_rtx, void *); static void note_sets (rtx, const_rtx, void *);
static void clear_dead_regs (HARD_REG_SET *, enum reg_note, rtx); static void clear_dead_regs (HARD_REG_SET *, enum reg_note, rtx);
static void merge_overlapping_regs (basic_block, HARD_REG_SET *, static void merge_overlapping_regs (basic_block, HARD_REG_SET *,
struct du_chain *); struct du_head *);
/* Called through note_stores. Find sets of registers, and /* Called through note_stores. Find sets of registers, and
record them in *DATA (which is actually a HARD_REG_SET *). */ record them in *DATA (which is actually a HARD_REG_SET *). */
...@@ -127,14 +147,14 @@ clear_dead_regs (HARD_REG_SET *pset, enum reg_note kind, rtx notes) ...@@ -127,14 +147,14 @@ clear_dead_regs (HARD_REG_SET *pset, enum reg_note kind, rtx notes)
} }
} }
/* For a def-use chain CHAIN in basic block B, find which registers overlap /* For a def-use chain HEAD in basic block B, find which registers overlap
its lifetime and set the corresponding bits in *PSET. */ its lifetime and set the corresponding bits in *PSET. */
static void static void
merge_overlapping_regs (basic_block b, HARD_REG_SET *pset, merge_overlapping_regs (basic_block b, HARD_REG_SET *pset,
struct du_chain *chain) struct du_head *head)
{ {
struct du_chain *t = chain; struct du_chain *t;
rtx insn; rtx insn;
HARD_REG_SET live; HARD_REG_SET live;
df_ref *def_rec; df_ref *def_rec;
...@@ -146,6 +166,8 @@ merge_overlapping_regs (basic_block b, HARD_REG_SET *pset, ...@@ -146,6 +166,8 @@ merge_overlapping_regs (basic_block b, HARD_REG_SET *pset,
if (DF_REF_FLAGS (def) & DF_REF_AT_TOP) if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
SET_HARD_REG_BIT (live, DF_REF_REGNO (def)); SET_HARD_REG_BIT (live, DF_REF_REGNO (def));
} }
t = head->first;
insn = BB_HEAD (b); insn = BB_HEAD (b);
while (t) while (t)
{ {
...@@ -159,7 +181,7 @@ merge_overlapping_regs (basic_block b, HARD_REG_SET *pset, ...@@ -159,7 +181,7 @@ merge_overlapping_regs (basic_block b, HARD_REG_SET *pset,
note_stores (PATTERN (insn), note_sets, (void *) &live); note_stores (PATTERN (insn), note_sets, (void *) &live);
/* Only record currently live regs if we are inside the /* Only record currently live regs if we are inside the
reg's live range. */ reg's live range. */
if (t != chain) if (t != head->first)
IOR_HARD_REG_SET (*pset, live); IOR_HARD_REG_SET (*pset, live);
clear_dead_regs (&live, REG_UNUSED, REG_NOTES (insn)); clear_dead_regs (&live, REG_UNUSED, REG_NOTES (insn));
} }
...@@ -200,7 +222,7 @@ regrename_optimize (void) ...@@ -200,7 +222,7 @@ regrename_optimize (void)
FOR_EACH_BB (bb) FOR_EACH_BB (bb)
{ {
struct du_chain *all_chains = 0; struct du_head *all_chains = 0;
HARD_REG_SET unavailable; HARD_REG_SET unavailable;
HARD_REG_SET regs_seen; HARD_REG_SET regs_seen;
...@@ -229,13 +251,13 @@ regrename_optimize (void) ...@@ -229,13 +251,13 @@ regrename_optimize (void)
{ {
int new_reg, best_new_reg; int new_reg, best_new_reg;
int n_uses; int n_uses;
struct du_chain *this_du = all_chains; struct du_head *this_head = all_chains;
struct du_chain *tmp; struct du_chain *tmp;
HARD_REG_SET this_unavailable; HARD_REG_SET this_unavailable;
int reg = REGNO (*this_du->loc); int reg = this_head->regno;
int i; int i;
all_chains = this_du->next_chain; all_chains = this_head->next_chain;
best_new_reg = reg; best_new_reg = reg;
...@@ -262,7 +284,7 @@ regrename_optimize (void) ...@@ -262,7 +284,7 @@ regrename_optimize (void)
/* Count number of uses, and narrow the set of registers we can /* Count number of uses, and narrow the set of registers we can
use for renaming. */ use for renaming. */
n_uses = 0; n_uses = 0;
for (tmp = this_du; tmp; tmp = tmp->next_use) for (tmp = this_head->first; tmp; tmp = tmp->next_use)
{ {
if (DEBUG_INSN_P (tmp->insn)) if (DEBUG_INSN_P (tmp->insn))
continue; continue;
...@@ -274,16 +296,17 @@ regrename_optimize (void) ...@@ -274,16 +296,17 @@ regrename_optimize (void)
if (n_uses < 2) if (n_uses < 2)
continue; continue;
if (this_du->need_caller_save_reg) if (this_head->need_caller_save_reg)
IOR_HARD_REG_SET (this_unavailable, call_used_reg_set); IOR_HARD_REG_SET (this_unavailable, call_used_reg_set);
merge_overlapping_regs (bb, &this_unavailable, this_du); merge_overlapping_regs (bb, &this_unavailable, this_head);
/* Now potential_regs is a reasonable approximation, let's /* Now potential_regs is a reasonable approximation, let's
have a closer look at each register still in there. */ have a closer look at each register still in there. */
for (new_reg = 0; new_reg < FIRST_PSEUDO_REGISTER; new_reg++) for (new_reg = 0; new_reg < FIRST_PSEUDO_REGISTER; new_reg++)
{ {
int nregs = hard_regno_nregs[new_reg][GET_MODE (*this_du->loc)]; enum machine_mode mode = GET_MODE (*this_head->first->loc);
int nregs = hard_regno_nregs[new_reg][mode];
for (i = nregs - 1; i >= 0; --i) for (i = nregs - 1; i >= 0; --i)
if (TEST_HARD_REG_BIT (this_unavailable, new_reg + i) if (TEST_HARD_REG_BIT (this_unavailable, new_reg + i)
...@@ -308,10 +331,10 @@ regrename_optimize (void) ...@@ -308,10 +331,10 @@ regrename_optimize (void)
/* See whether it accepts all modes that occur in /* See whether it accepts all modes that occur in
definition and uses. */ definition and uses. */
for (tmp = this_du; tmp; tmp = tmp->next_use) for (tmp = this_head->first; tmp; tmp = tmp->next_use)
if ((! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc)) if ((! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc))
&& ! DEBUG_INSN_P (tmp->insn)) && ! DEBUG_INSN_P (tmp->insn))
|| (tmp->need_caller_save_reg || (this_head->need_caller_save_reg
&& ! (HARD_REGNO_CALL_PART_CLOBBERED && ! (HARD_REGNO_CALL_PART_CLOBBERED
(reg, GET_MODE (*tmp->loc))) (reg, GET_MODE (*tmp->loc)))
&& (HARD_REGNO_CALL_PART_CLOBBERED && (HARD_REGNO_CALL_PART_CLOBBERED
...@@ -327,8 +350,8 @@ regrename_optimize (void) ...@@ -327,8 +350,8 @@ regrename_optimize (void)
if (dump_file) if (dump_file)
{ {
fprintf (dump_file, "Register %s in insn %d", fprintf (dump_file, "Register %s in insn %d",
reg_names[reg], INSN_UID (this_du->insn)); reg_names[reg], INSN_UID (this_head->first->insn));
if (this_du->need_caller_save_reg) if (this_head->need_caller_save_reg)
fprintf (dump_file, " crosses a call"); fprintf (dump_file, " crosses a call");
} }
...@@ -343,7 +366,7 @@ regrename_optimize (void) ...@@ -343,7 +366,7 @@ regrename_optimize (void)
if (dump_file) if (dump_file)
fprintf (dump_file, ", renamed as %s\n", reg_names[best_new_reg]); fprintf (dump_file, ", renamed as %s\n", reg_names[best_new_reg]);
do_replace (this_du, best_new_reg); do_replace (this_head, best_new_reg);
tick[best_new_reg] = ++this_tick; tick[best_new_reg] = ++this_tick;
df_set_regs_ever_live (best_new_reg, true); df_set_regs_ever_live (best_new_reg, true);
} }
...@@ -360,16 +383,17 @@ regrename_optimize (void) ...@@ -360,16 +383,17 @@ regrename_optimize (void)
} }
static void static void
do_replace (struct du_chain *chain, int reg) do_replace (struct du_head *head, int reg)
{ {
unsigned int base_regno = REGNO (*chain->loc); struct du_chain *chain;
unsigned int base_regno = head->regno;
gcc_assert (! DEBUG_INSN_P (chain->insn)); gcc_assert (! DEBUG_INSN_P (head->first->insn));
while (chain) for (chain = head->first; chain; chain = chain->next_use)
{ {
unsigned int regno = ORIGINAL_REGNO (*chain->loc); unsigned int regno = ORIGINAL_REGNO (*chain->loc);
struct reg_attrs * attr = REG_ATTRS (*chain->loc); struct reg_attrs *attr = REG_ATTRS (*chain->loc);
int reg_ptr = REG_POINTER (*chain->loc); int reg_ptr = REG_POINTER (*chain->loc);
if (DEBUG_INSN_P (chain->insn) && REGNO (*chain->loc) != base_regno) if (DEBUG_INSN_P (chain->insn) && REGNO (*chain->loc) != base_regno)
...@@ -399,37 +423,42 @@ do_replace (struct du_chain *chain, int reg) ...@@ -399,37 +423,42 @@ do_replace (struct du_chain *chain, int reg)
} }
df_insn_rescan (chain->insn); df_insn_rescan (chain->insn);
chain = chain->next_use;
} }
} }
static struct du_chain *open_chains; static struct du_head *open_chains;
static struct du_chain *closed_chains; static struct du_head *closed_chains;
static void static void
scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl,
enum scan_actions action, enum op_type type, int earlyclobber) enum scan_actions action, enum op_type type, int earlyclobber)
{ {
struct du_chain **p; struct du_head **p;
rtx x = *loc; rtx x = *loc;
enum machine_mode mode = GET_MODE (x); enum machine_mode mode = GET_MODE (x);
int this_regno = REGNO (x); unsigned this_regno = REGNO (x);
int this_nregs = hard_regno_nregs[this_regno][mode]; unsigned this_nregs = hard_regno_nregs[this_regno][mode];
if (action == mark_write) if (action == mark_write)
{ {
if (type == OP_OUT) if (type == OP_OUT)
{ {
struct du_head *head = XOBNEW (&rename_obstack, struct du_head);
struct du_chain *this_du = XOBNEW (&rename_obstack, struct du_chain); struct du_chain *this_du = XOBNEW (&rename_obstack, struct du_chain);
head->next_chain = open_chains;
open_chains = head;
head->first = head->last = this_du;
head->regno = this_regno;
head->nregs = this_nregs;
head->need_caller_save_reg = 0;
head->terminated = 0;
this_du->next_use = 0; this_du->next_use = 0;
this_du->next_chain = open_chains;
this_du->loc = loc; this_du->loc = loc;
this_du->insn = insn; this_du->insn = insn;
this_du->cl = cl; this_du->cl = cl;
this_du->need_caller_save_reg = 0;
this_du->earlyclobber = earlyclobber; this_du->earlyclobber = earlyclobber;
open_chains = this_du;
} }
return; return;
} }
...@@ -439,7 +468,7 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, ...@@ -439,7 +468,7 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl,
for (p = &open_chains; *p;) for (p = &open_chains; *p;)
{ {
struct du_chain *this_du = *p; struct du_head *head = *p;
/* Check if the chain has been terminated if it has then skip to /* Check if the chain has been terminated if it has then skip to
the next chain. the next chain.
...@@ -448,18 +477,17 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, ...@@ -448,18 +477,17 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl,
the chain in Step 3, but are trying to hide in-out operands the chain in Step 3, but are trying to hide in-out operands
from terminate_write in Step 5. */ from terminate_write in Step 5. */
if (*this_du->loc == cc0_rtx) if (head->terminated)
p = &this_du->next_chain; p = &head->next_chain;
else else
{ {
int regno = REGNO (*this_du->loc); int exact_match = (head->regno == this_regno
int nregs = hard_regno_nregs[regno][GET_MODE (*this_du->loc)]; && head->nregs == this_nregs);
int exact_match = (regno == this_regno && nregs == this_nregs);
if (regno + nregs <= this_regno if (head->regno + head->nregs <= this_regno
|| this_regno + this_nregs <= regno) || this_regno + this_nregs <= head->regno)
{ {
p = &this_du->next_chain; p = &head->next_chain;
continue; continue;
} }
...@@ -473,37 +501,36 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, ...@@ -473,37 +501,36 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl,
be replaced with, terminate the chain. */ be replaced with, terminate the chain. */
if (cl != NO_REGS) if (cl != NO_REGS)
{ {
struct du_chain *this_du;
this_du = XOBNEW (&rename_obstack, struct du_chain); this_du = XOBNEW (&rename_obstack, struct du_chain);
this_du->next_use = 0; this_du->next_use = 0;
this_du->next_chain = (*p)->next_chain;
this_du->loc = loc; this_du->loc = loc;
this_du->insn = insn; this_du->insn = insn;
this_du->cl = cl; this_du->cl = cl;
this_du->need_caller_save_reg = 0; head->last->next_use = this_du;
while (*p) head->last = this_du;
p = &(*p)->next_use;
*p = this_du;
return; return;
} }
} }
if (action != terminate_overlapping_read || ! exact_match) if (action != terminate_overlapping_read || ! exact_match)
{ {
struct du_chain *next = this_du->next_chain; struct du_head *next = head->next_chain;
/* Whether the terminated chain can be used for renaming /* Whether the terminated chain can be used for renaming
depends on the action and this being an exact match. depends on the action and this being an exact match.
In either case, we remove this element from open_chains. */ In either case, we remove this element from open_chains. */
head->terminated = 1;
if ((action == terminate_dead || action == terminate_write) if ((action == terminate_dead || action == terminate_write)
&& exact_match) && exact_match)
{ {
this_du->next_chain = closed_chains; head->next_chain = closed_chains;
closed_chains = this_du; closed_chains = head;
if (dump_file) if (dump_file)
fprintf (dump_file, fprintf (dump_file,
"Closing chain %s at insn %d (%s)\n", "Closing chain %s at insn %d (%s)\n",
reg_names[REGNO (*this_du->loc)], INSN_UID (insn), reg_names[head->regno], INSN_UID (insn),
scan_actions_name[(int) action]); scan_actions_name[(int) action]);
} }
else else
...@@ -511,13 +538,13 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, ...@@ -511,13 +538,13 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl,
if (dump_file) if (dump_file)
fprintf (dump_file, fprintf (dump_file,
"Discarding chain %s at insn %d (%s)\n", "Discarding chain %s at insn %d (%s)\n",
reg_names[REGNO (*this_du->loc)], INSN_UID (insn), reg_names[head->regno], INSN_UID (insn),
scan_actions_name[(int) action]); scan_actions_name[(int) action]);
} }
*p = next; *p = next;
} }
else else
p = &this_du->next_chain; p = &head->next_chain;
} }
} }
} }
...@@ -760,7 +787,7 @@ scan_rtx (rtx insn, rtx *loc, enum reg_class cl, ...@@ -760,7 +787,7 @@ scan_rtx (rtx insn, rtx *loc, enum reg_class cl,
/* Build def/use chain. */ /* Build def/use chain. */
static struct du_chain * static struct du_head *
build_def_use (basic_block bb) build_def_use (basic_block bb)
{ {
rtx insn; rtx insn;
...@@ -914,7 +941,7 @@ build_def_use (basic_block bb) ...@@ -914,7 +941,7 @@ build_def_use (basic_block bb)
requires a caller-saved reg. */ requires a caller-saved reg. */
if (CALL_P (insn)) if (CALL_P (insn))
{ {
struct du_chain *p; struct du_head *p;
for (p = open_chains; p; p = p->next_chain) for (p = open_chains; p; p = p->next_chain)
p->need_caller_save_reg = 1; p->need_caller_save_reg = 1;
} }
...@@ -1014,14 +1041,13 @@ build_def_use (basic_block bb) ...@@ -1014,14 +1041,13 @@ build_def_use (basic_block bb)
printed in reverse order as that's how we build them. */ printed in reverse order as that's how we build them. */
static void static void
dump_def_use_chain (struct du_chain *chains) dump_def_use_chain (struct du_head *head)
{ {
while (chains) while (head)
{ {
struct du_chain *this_du = chains; struct du_chain *this_du = head->first;
int r = REGNO (*this_du->loc); fprintf (dump_file, "Register %s (%d):",
int nregs = hard_regno_nregs[r][GET_MODE (*this_du->loc)]; reg_names[head->regno], head->nregs);
fprintf (dump_file, "Register %s (%d):", reg_names[r], nregs);
while (this_du) while (this_du)
{ {
fprintf (dump_file, " %d [%s]", INSN_UID (this_du->insn), fprintf (dump_file, " %d [%s]", INSN_UID (this_du->insn),
...@@ -1029,7 +1055,7 @@ dump_def_use_chain (struct du_chain *chains) ...@@ -1029,7 +1055,7 @@ dump_def_use_chain (struct du_chain *chains)
this_du = this_du->next_use; this_du = this_du->next_use;
} }
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
chains = chains->next_chain; head = head->next_chain;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment