Commit 8ffa0351 by Bernd Schmidt Committed by Bernd Schmidt

regrename.c (struct du_head): Make nregs signed.

	* regrename.c (struct du_head): Make nregs signed.
	(closed_chains): Remove.
	(create_new_chain): Return the new chain.
	(chain_from_id): New static function.
	(dump_def_use_chain): Change argument to be an int, indicating
	the first ID to print.  All callers changed.
	(merge_overlapping_regs): Use chain_from_id.  Assert that
	chains don't conflict with themselves.
	(rename_chains): Take no argument.  Iterate over id_to_chain
	rather to find chains to rename.  Clear tick before the main
	loop.
	(struct incoming_reg_info): New struct.
	(struct bb_rename_info): New struct.
	(init_rename_info, set_incoming_from_chain, merge_chains): New
	static functions.
	(regrename_analyze): New static function, broken out of
	regrename_optimize.  Record and make use of open chain information
	at basic block boundaries, and merge chains where possible.
	(scan_rtx_reg): Make this_nregs signed.  Don't update
	closed_chains.
	(build_def_use): Return a bool to indicate success.  All callers
	changed.  Don't initialize global data here.
	(regrename_optimize): Move most code out of here into
	regrename_analyze.
	* regs.h (add_range_to_hard_reg_set, remove_range_from_hard_reg_set,
	range_overlaps_hard_reg_set_p, range_in_hard_reg_set_p): New
	static inline functions.
	* vec.h (FOR_EACH_VEC_ELT_FROM): New macro.

From-SVN: r178645
parent a81462f1
2011-09-07 Bernd Schmidt <bernds@codesourcery.com>
* regrename.c (struct du_head): Make nregs signed.
(closed_chains): Remove.
(create_new_chain): Return the new chain.
(chain_from_id): New static function.
(dump_def_use_chain): Change argument to be an int, indicating
the first ID to print. All callers changed.
(merge_overlapping_regs): Use chain_from_id. Assert that
chains don't conflict with themselves.
(rename_chains): Take no argument. Iterate over id_to_chain
rather to find chains to rename. Clear tick before the main
loop.
(struct incoming_reg_info): New struct.
(struct bb_rename_info): New struct.
(init_rename_info, set_incoming_from_chain, merge_chains): New
static functions.
(regrename_analyze): New static function, broken out of
regrename_optimize. Record and make use of open chain information
at basic block boundaries, and merge chains where possible.
(scan_rtx_reg): Make this_nregs signed. Don't update
closed_chains.
(build_def_use): Return a bool to indicate success. All callers
changed. Don't initialize global data here.
(regrename_optimize): Move most code out of here into
regrename_analyze.
* regs.h (add_range_to_hard_reg_set, remove_range_from_hard_reg_set,
range_overlaps_hard_reg_set_p, range_in_hard_reg_set_p): New
static inline functions.
* vec.h (FOR_EACH_VEC_ELT_FROM): New macro.
2011-09-07 Martin Jambor <mjambor@suse.cz> 2011-09-07 Martin Jambor <mjambor@suse.cz>
PR middle-end/50301 PR middle-end/50301
...@@ -47,18 +47,24 @@ ...@@ -47,18 +47,24 @@
1. Local def/use chains are built: within each basic block, chains are 1. Local def/use chains are built: within each basic block, chains are
opened and closed; if a chain isn't closed at the end of the block, opened and closed; if a chain isn't closed at the end of the block,
it is dropped. it is dropped. We pre-open chains if we have already examined a
predecessor block and found chains live at the end which match
live registers at the start of the new block.
2. For each chain, the set of possible renaming registers is computed. 2. We try to combine the local chains across basic block boundaries by
comparing chains that were open at the start or end of a block to
those in successor/predecessor blocks.
3. For each chain, the set of possible renaming registers is computed.
This takes into account the renaming of previously processed chains. This takes into account the renaming of previously processed chains.
Optionally, a preferred class is computed for the renaming register. Optionally, a preferred class is computed for the renaming register.
3. The best renaming register is computed for the chain in the above set, 4. The best renaming register is computed for the chain in the above set,
using a round-robin allocation. If a preferred class exists, then the using a round-robin allocation. If a preferred class exists, then the
round-robin allocation is done within the class first, if possible. round-robin allocation is done within the class first, if possible.
The round-robin allocation of renaming registers itself is global. The round-robin allocation of renaming registers itself is global.
4. If a renaming register has been found, it is substituted in the chain. 5. If a renaming register has been found, it is substituted in the chain.
Targets can parameterize the pass by specifying a preferred class for the Targets can parameterize the pass by specifying a preferred class for the
renaming register for a given (super)class of registers to be renamed. */ renaming register for a given (super)class of registers to be renamed. */
...@@ -75,8 +81,9 @@ struct du_head ...@@ -75,8 +81,9 @@ struct du_head
struct du_head *next_chain; struct du_head *next_chain;
/* The first and last elements of this chain. */ /* The first and last elements of this chain. */
struct du_chain *first, *last; struct du_chain *first, *last;
/* Describes the register being tracked. */ /* Describe the register being tracked, register number and count. */
unsigned regno, nregs; unsigned regno;
int nregs;
/* A unique id to be used as an index into the conflicts bitmaps. */ /* A unique id to be used as an index into the conflicts bitmaps. */
unsigned id; unsigned id;
...@@ -140,6 +147,7 @@ static struct obstack rename_obstack; ...@@ -140,6 +147,7 @@ static struct obstack rename_obstack;
static void do_replace (struct du_head *, int); static void do_replace (struct du_head *, int);
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); enum op_type);
static bool build_def_use (basic_block);
typedef struct du_head *du_head_p; typedef struct du_head *du_head_p;
DEF_VEC_P (du_head_p); DEF_VEC_P (du_head_p);
...@@ -151,9 +159,8 @@ static unsigned current_id; ...@@ -151,9 +159,8 @@ static unsigned current_id;
/* A mapping of unique id numbers to chains. */ /* A mapping of unique id numbers to chains. */
static VEC(du_head_p, heap) *id_to_chain; static VEC(du_head_p, heap) *id_to_chain;
/* List of currently open chains, and closed chains that can be renamed. */ /* List of currently open chains. */
static struct du_head *open_chains; 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 /* Bitmap of open chains. The bits set always match the list found in
open_chains. */ open_chains. */
...@@ -166,14 +173,33 @@ static HARD_REG_SET live_in_chains; ...@@ -166,14 +173,33 @@ static HARD_REG_SET live_in_chains;
between this and live_in_chains is empty. */ between this and live_in_chains is empty. */
static HARD_REG_SET live_hard_regs; static HARD_REG_SET live_hard_regs;
/* Dump all def/use chains in CHAINS to DUMP_FILE. */ /* Return the chain corresponding to id number ID. Take into account that
chains may have been merged. */
static du_head_p
chain_from_id (unsigned int id)
{
du_head_p first_chain = VEC_index (du_head_p, id_to_chain, id);
du_head_p chain = first_chain;
while (chain->id != id)
{
id = chain->id;
chain = VEC_index (du_head_p, id_to_chain, id);
}
first_chain->id = id;
return chain;
}
/* Dump all def/use chains, starting at id FROM. */
static void static void
dump_def_use_chain (struct du_head *head) dump_def_use_chain (int from)
{ {
while (head) du_head_p head;
int i;
FOR_EACH_VEC_ELT_FROM (du_head_p, id_to_chain, i, head, from)
{ {
struct du_chain *this_du = head->first; struct du_chain *this_du = head->first;
fprintf (dump_file, "Register %s (%d):", fprintf (dump_file, "Register %s (%d):",
reg_names[head->regno], head->nregs); reg_names[head->regno], head->nregs);
while (this_du) while (this_du)
...@@ -215,7 +241,7 @@ mark_conflict (struct du_head *chains, unsigned id) ...@@ -215,7 +241,7 @@ mark_conflict (struct du_head *chains, unsigned id)
and record its occurrence in *LOC, which is being written to in INSN. and record its occurrence in *LOC, which is being written to in INSN.
This access requires a register of class CL. */ This access requires a register of class CL. */
static void static du_head_p
create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc, create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc,
rtx insn, enum reg_class cl) rtx insn, enum reg_class cl)
{ {
...@@ -224,7 +250,6 @@ create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc, ...@@ -224,7 +250,6 @@ create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc,
int nregs; int nregs;
head->next_chain = open_chains; head->next_chain = open_chains;
open_chains = head;
head->regno = this_regno; head->regno = this_regno;
head->nregs = this_nregs; head->nregs = this_nregs;
head->need_caller_save_reg = 0; head->need_caller_save_reg = 0;
...@@ -264,7 +289,7 @@ create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc, ...@@ -264,7 +289,7 @@ create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc,
if (insn == NULL_RTX) if (insn == NULL_RTX)
{ {
head->first = head->last = NULL; head->first = head->last = NULL;
return; return head;
} }
this_du = XOBNEW (&rename_obstack, struct du_chain); this_du = XOBNEW (&rename_obstack, struct du_chain);
...@@ -274,6 +299,7 @@ create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc, ...@@ -274,6 +299,7 @@ create_new_chain (unsigned this_regno, unsigned this_nregs, rtx *loc,
this_du->loc = loc; this_du->loc = loc;
this_du->insn = insn; this_du->insn = insn;
this_du->cl = cl; this_du->cl = cl;
return head;
} }
/* For a def-use chain HEAD, find which registers overlap its lifetime and /* For a def-use chain HEAD, find which registers overlap its lifetime and
...@@ -287,8 +313,9 @@ merge_overlapping_regs (HARD_REG_SET *pset, struct du_head *head) ...@@ -287,8 +313,9 @@ merge_overlapping_regs (HARD_REG_SET *pset, struct du_head *head)
IOR_HARD_REG_SET (*pset, head->hard_conflicts); IOR_HARD_REG_SET (*pset, head->hard_conflicts);
EXECUTE_IF_SET_IN_BITMAP (&head->conflicts, 0, i, bi) EXECUTE_IF_SET_IN_BITMAP (&head->conflicts, 0, i, bi)
{ {
du_head_p other = VEC_index (du_head_p, id_to_chain, i); du_head_p other = chain_from_id (i);
unsigned j = other->nregs; unsigned j = other->nregs;
gcc_assert (other != head);
while (j-- > 0) while (j-- > 0)
SET_HARD_REG_BIT (*pset, other->regno + j); SET_HARD_REG_BIT (*pset, other->regno + j);
} }
...@@ -341,12 +368,15 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg, ...@@ -341,12 +368,15 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg,
return true; return true;
} }
/* Process the closed chains starting with ALL_CHAINS and rename /* Perform register renaming on the current function. */
registers if possible. */
static void static void
rename_chains (du_head_p all_chains) rename_chains (void)
{ {
HARD_REG_SET unavailable; HARD_REG_SET unavailable;
du_head_p this_head;
int i;
memset (tick, 0, sizeof tick);
CLEAR_HARD_REG_SET (unavailable); CLEAR_HARD_REG_SET (unavailable);
/* Don't clobber traceback for noreturn functions. */ /* Don't clobber traceback for noreturn functions. */
...@@ -358,11 +388,10 @@ rename_chains (du_head_p all_chains) ...@@ -358,11 +388,10 @@ rename_chains (du_head_p all_chains)
#endif #endif
} }
while (all_chains) FOR_EACH_VEC_ELT (du_head_p, id_to_chain, i, this_head)
{ {
int new_reg, best_new_reg, best_nregs; int new_reg, best_new_reg, best_nregs;
int n_uses; int n_uses;
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 = this_head->regno; int reg = this_head->regno;
...@@ -371,8 +400,6 @@ rename_chains (du_head_p all_chains) ...@@ -371,8 +400,6 @@ rename_chains (du_head_p all_chains)
enum reg_class preferred_class; enum reg_class preferred_class;
bool has_preferred_class; bool has_preferred_class;
all_chains = this_head->next_chain;
if (this_head->cannot_rename) if (this_head->cannot_rename)
continue; continue;
...@@ -488,14 +515,425 @@ rename_chains (du_head_p all_chains) ...@@ -488,14 +515,425 @@ rename_chains (du_head_p all_chains)
} }
} }
/* A structure to record information for each hard register at the start of
a basic block. */
struct incoming_reg_info {
/* Holds the number of registers used in the chain that gave us information
about this register. Zero means no information known yet, while a
negative value is used for something that is part of, but not the first
register in a multi-register value. */
int nregs;
/* Set to true if we have accesses that conflict in the number of registers
used. */
bool unusable;
};
/* A structure recording information about each basic block. It is saved
and restored around basic block boundaries.
A pointer to such a structure is stored in each basic block's aux field
during regrename_analyze, except for blocks we know can't be optimized
(such as entry and exit blocks). */
struct bb_rename_info
{
/* The basic block corresponding to this structure. */
basic_block bb;
/* Copies of the global information. */
bitmap_head open_chains_set;
bitmap_head incoming_open_chains_set;
struct incoming_reg_info incoming[FIRST_PSEUDO_REGISTER];
};
/* Initialize a rename_info structure P for basic block BB, which starts a new
scan. */
static void
init_rename_info (struct bb_rename_info *p, basic_block bb)
{
int i;
df_ref *def_rec;
HARD_REG_SET start_chains_set;
p->bb = bb;
bitmap_initialize (&p->open_chains_set, &bitmap_default_obstack);
bitmap_initialize (&p->incoming_open_chains_set, &bitmap_default_obstack);
open_chains = NULL;
bitmap_clear (&open_chains_set);
CLEAR_HARD_REG_SET (live_in_chains);
REG_SET_TO_HARD_REG_SET (live_hard_regs, df_get_live_in (bb));
for (def_rec = df_get_artificial_defs (bb->index); *def_rec; def_rec++)
{
df_ref def = *def_rec;
if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
SET_HARD_REG_BIT (live_hard_regs, DF_REF_REGNO (def));
}
/* Open chains based on information from (at least one) predecessor
block. This gives us a chance later on to combine chains across
basic block boundaries. Inconsistencies (in access sizes) will
be caught normally and dealt with conservatively by disabling the
chain for renaming, and there is no risk of losing optimization
opportunities by opening chains either: if we did not open the
chains, we'd have to track the live register as a hard reg, and
we'd be unable to rename it in any case. */
CLEAR_HARD_REG_SET (start_chains_set);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
struct incoming_reg_info *iri = p->incoming + i;
if (iri->nregs > 0 && !iri->unusable
&& range_in_hard_reg_set_p (live_hard_regs, i, iri->nregs))
{
SET_HARD_REG_BIT (start_chains_set, i);
remove_range_from_hard_reg_set (&live_hard_regs, i, iri->nregs);
}
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
struct incoming_reg_info *iri = p->incoming + i;
if (TEST_HARD_REG_BIT (start_chains_set, i))
{
du_head_p chain;
if (dump_file)
fprintf (dump_file, "opening incoming chain\n");
chain = create_new_chain (i, iri->nregs, NULL, NULL_RTX, NO_REGS);
bitmap_set_bit (&p->incoming_open_chains_set, chain->id);
}
}
}
/* Record in RI that the block corresponding to it has an incoming
live value, described by CHAIN. */
static void
set_incoming_from_chain (struct bb_rename_info *ri, du_head_p chain)
{
int i;
int incoming_nregs = ri->incoming[chain->regno].nregs;
int nregs;
/* If we've recorded the same information before, everything is fine. */
if (incoming_nregs == chain->nregs)
{
if (dump_file)
fprintf (dump_file, "reg %d/%d already recorded\n",
chain->regno, chain->nregs);
return;
}
/* If we have no information for any of the involved registers, update
the incoming array. */
nregs = chain->nregs;
while (nregs-- > 0)
if (ri->incoming[chain->regno + nregs].nregs != 0
|| ri->incoming[chain->regno + nregs].unusable)
break;
if (nregs < 0)
{
nregs = chain->nregs;
ri->incoming[chain->regno].nregs = nregs;
while (nregs-- > 1)
ri->incoming[chain->regno + nregs].nregs = -nregs;
if (dump_file)
fprintf (dump_file, "recorded reg %d/%d\n",
chain->regno, chain->nregs);
return;
}
/* There must be some kind of conflict. Prevent both the old and
new ranges from being used. */
if (incoming_nregs < 0)
ri->incoming[chain->regno + incoming_nregs].unusable = true;
for (i = 0; i < chain->nregs; i++)
ri->incoming[chain->regno + i].unusable = true;
}
/* Merge the two chains C1 and C2 so that all conflict information is
recorded and C1, and the id of C2 is changed to that of C1. */
static void
merge_chains (du_head_p c1, du_head_p c2)
{
if (c1 == c2)
return;
if (c2->first != NULL)
{
if (c1->first == NULL)
c1->first = c2->first;
else
c1->last->next_use = c2->first;
c1->last = c2->last;
}
c2->first = c2->last = NULL;
c2->id = c1->id;
IOR_HARD_REG_SET (c1->hard_conflicts, c2->hard_conflicts);
bitmap_ior_into (&c1->conflicts, &c2->conflicts);
c1->need_caller_save_reg |= c2->need_caller_save_reg;
c1->cannot_rename |= c2->cannot_rename;
}
/* Analyze the current function and build chains for renaming. */
static void
regrename_analyze (void)
{
struct bb_rename_info *rename_info;
int i;
basic_block bb;
int n_bbs;
int *inverse_postorder;
inverse_postorder = XNEWVEC (int, last_basic_block);
n_bbs = pre_and_rev_post_order_compute (NULL, inverse_postorder, false);
/* Gather some information about the blocks in this function. */
rename_info = XCNEWVEC (struct bb_rename_info, n_basic_blocks);
i = 0;
FOR_EACH_BB (bb)
{
struct bb_rename_info *ri = rename_info + i;
ri->bb = bb;
bb->aux = ri;
i++;
}
current_id = 0;
id_to_chain = VEC_alloc (du_head_p, heap, 0);
bitmap_initialize (&open_chains_set, &bitmap_default_obstack);
/* The order in which we visit blocks ensures that whenever
possible, we only process a block after at least one of its
predecessors, which provides a "seeding" effect to make the logic
in set_incoming_from_chain and init_rename_info useful. */
for (i = 0; i < n_bbs; i++)
{
basic_block bb1 = BASIC_BLOCK (inverse_postorder[i]);
struct bb_rename_info *this_info;
bool success;
edge e;
edge_iterator ei;
int old_length = VEC_length (du_head_p, id_to_chain);
this_info = (struct bb_rename_info *) bb1->aux;
if (this_info == NULL)
continue;
if (dump_file)
fprintf (dump_file, "\nprocessing block %d:\n", bb1->index);
init_rename_info (this_info, bb1);
success = build_def_use (bb1);
if (!success)
{
if (dump_file)
fprintf (dump_file, "failed\n");
bb1->aux = NULL;
VEC_truncate (du_head_p, id_to_chain, old_length);
current_id = old_length;
bitmap_clear (&this_info->incoming_open_chains_set);
open_chains = NULL;
continue;
}
if (dump_file)
dump_def_use_chain (old_length);
bitmap_copy (&this_info->open_chains_set, &open_chains_set);
/* Add successor blocks to the worklist if necessary, and record
data about our own open chains at the end of this block, which
will be used to pre-open chains when processing the successors. */
FOR_EACH_EDGE (e, ei, bb1->succs)
{
struct bb_rename_info *dest_ri;
struct du_head *chain;
if (dump_file)
fprintf (dump_file, "successor block %d\n", e->dest->index);
if (e->flags & (EDGE_EH | EDGE_ABNORMAL))
continue;
dest_ri = (struct bb_rename_info *)e->dest->aux;
if (dest_ri == NULL)
continue;
for (chain = open_chains; chain; chain = chain->next_chain)
set_incoming_from_chain (dest_ri, chain);
}
}
free (inverse_postorder);
/* Now, combine the chains data we have gathered across basic block
boundaries.
For every basic block, there may be chains open at the start, or at the
end. Rather than exclude them from renaming, we look for open chains
with matching registers at the other side of the CFG edge.
For a given chain using register R, open at the start of block B, we
must find an open chain using R on the other side of every edge leading
to B, if the register is live across this edge. In the code below,
N_PREDS_USED counts the number of edges where the register is live, and
N_PREDS_JOINED counts those where we found an appropriate chain for
joining.
We perform the analysis for both incoming and outgoing edges, but we
only need to merge once (in the second part, after verifying outgoing
edges). */
FOR_EACH_BB (bb)
{
struct bb_rename_info *bb_ri = (struct bb_rename_info *) bb->aux;
unsigned j;
bitmap_iterator bi;
if (bb_ri == NULL)
continue;
if (dump_file)
fprintf (dump_file, "processing bb %d in edges\n", bb->index);
EXECUTE_IF_SET_IN_BITMAP (&bb_ri->incoming_open_chains_set, 0, j, bi)
{
edge e;
edge_iterator ei;
struct du_head *chain = chain_from_id (j);
int n_preds_used = 0, n_preds_joined = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
{
struct bb_rename_info *src_ri;
unsigned k;
bitmap_iterator bi2;
HARD_REG_SET live;
bool success = false;
REG_SET_TO_HARD_REG_SET (live, df_get_live_out (e->src));
if (!range_overlaps_hard_reg_set_p (live, chain->regno,
chain->nregs))
continue;
n_preds_used++;
if (e->flags & (EDGE_EH | EDGE_ABNORMAL))
continue;
src_ri = (struct bb_rename_info *)e->src->aux;
if (src_ri == NULL)
continue;
EXECUTE_IF_SET_IN_BITMAP (&src_ri->open_chains_set,
0, k, bi2)
{
struct du_head *outgoing_chain = chain_from_id (k);
if (outgoing_chain->regno == chain->regno
&& outgoing_chain->nregs == chain->nregs)
{
n_preds_joined++;
success = true;
break;
}
}
if (!success && dump_file)
fprintf (dump_file, "failure to match with pred block %d\n",
e->src->index);
}
if (n_preds_joined < n_preds_used)
{
if (dump_file)
fprintf (dump_file, "cannot rename chain %d\n", j);
chain->cannot_rename = 1;
}
}
}
FOR_EACH_BB (bb)
{
struct bb_rename_info *bb_ri = (struct bb_rename_info *) bb->aux;
unsigned j;
bitmap_iterator bi;
if (bb_ri == NULL)
continue;
if (dump_file)
fprintf (dump_file, "processing bb %d out edges\n", bb->index);
EXECUTE_IF_SET_IN_BITMAP (&bb_ri->open_chains_set, 0, j, bi)
{
edge e;
edge_iterator ei;
struct du_head *chain = chain_from_id (j);
int n_succs_used = 0, n_succs_joined = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
{
bool printed = false;
struct bb_rename_info *dest_ri;
unsigned k;
bitmap_iterator bi2;
HARD_REG_SET live;
REG_SET_TO_HARD_REG_SET (live, df_get_live_in (e->dest));
if (!range_overlaps_hard_reg_set_p (live, chain->regno,
chain->nregs))
continue;
n_succs_used++;
dest_ri = (struct bb_rename_info *)e->dest->aux;
if (dest_ri == NULL)
continue;
EXECUTE_IF_SET_IN_BITMAP (&dest_ri->incoming_open_chains_set,
0, k, bi2)
{
struct du_head *incoming_chain = chain_from_id (k);
if (incoming_chain->regno == chain->regno
&& incoming_chain->nregs == chain->nregs)
{
if (dump_file)
{
if (!printed)
fprintf (dump_file,
"merging blocks for edge %d -> %d\n",
e->src->index, e->dest->index);
printed = true;
fprintf (dump_file,
" merging chains %d (->%d) and %d (->%d) [%s]\n",
k, incoming_chain->id, j, chain->id,
reg_names[incoming_chain->regno]);
}
merge_chains (chain, incoming_chain);
n_succs_joined++;
break;
}
}
}
if (n_succs_joined < n_succs_used)
{
if (dump_file)
fprintf (dump_file, "cannot rename chain %d\n",
j);
chain->cannot_rename = 1;
}
}
}
free (rename_info);
FOR_EACH_BB (bb)
bb->aux = NULL;
}
static void static void
do_replace (struct du_head *head, int reg) do_replace (struct du_head *head, int reg)
{ {
struct du_chain *chain; struct du_chain *chain;
unsigned int base_regno = head->regno; unsigned int base_regno = head->regno;
gcc_assert (! DEBUG_INSN_P (head->first->insn));
for (chain = head->first; chain; chain = chain->next_use) for (chain = head->first; chain; chain = chain->next_use)
{ {
unsigned int regno = ORIGINAL_REGNO (*chain->loc); unsigned int regno = ORIGINAL_REGNO (*chain->loc);
...@@ -591,7 +1029,7 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action, ...@@ -591,7 +1029,7 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
rtx x = *loc; rtx x = *loc;
enum machine_mode mode = GET_MODE (x); enum machine_mode mode = GET_MODE (x);
unsigned this_regno = REGNO (x); unsigned this_regno = REGNO (x);
unsigned this_nregs = hard_regno_nregs[this_regno][mode]; int this_nregs = hard_regno_nregs[this_regno][mode];
if (action == mark_write) if (action == mark_write)
{ {
...@@ -691,8 +1129,6 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action, ...@@ -691,8 +1129,6 @@ scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl, enum scan_actions action,
if (subset && !superset) if (subset && !superset)
head->cannot_rename = 1; head->cannot_rename = 1;
head->next_chain = closed_chains;
closed_chains = head;
bitmap_clear_bit (&open_chains_set, head->id); bitmap_clear_bit (&open_chains_set, head->id);
nregs = head->nregs; nregs = head->nregs;
...@@ -1078,28 +1514,14 @@ record_out_operands (rtx insn, bool earlyclobber) ...@@ -1078,28 +1514,14 @@ record_out_operands (rtx insn, bool earlyclobber)
/* Build def/use chain. */ /* Build def/use chain. */
static struct du_head * static bool
build_def_use (basic_block bb) build_def_use (basic_block bb)
{ {
rtx insn; rtx insn;
df_ref *def_rec;
unsigned HOST_WIDE_INT untracked_operands; unsigned HOST_WIDE_INT untracked_operands;
open_chains = closed_chains = NULL;
fail_current_block = false; fail_current_block = false;
current_id = 0;
bitmap_initialize (&open_chains_set, &bitmap_default_obstack);
CLEAR_HARD_REG_SET (live_in_chains);
REG_SET_TO_HARD_REG_SET (live_hard_regs, df_get_live_in (bb));
for (def_rec = df_get_artificial_defs (bb->index); *def_rec; def_rec++)
{
df_ref def = *def_rec;
if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
SET_HARD_REG_BIT (live_hard_regs, DF_REF_REGNO (def));
}
for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn)) for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
{ {
if (NONDEBUG_INSN_P (insn)) if (NONDEBUG_INSN_P (insn))
...@@ -1338,14 +1760,10 @@ build_def_use (basic_block bb) ...@@ -1338,14 +1760,10 @@ build_def_use (basic_block bb)
break; break;
} }
bitmap_clear (&open_chains_set);
if (fail_current_block) if (fail_current_block)
return NULL; return false;
/* Since we close every chain when we find a REG_DEAD note, anything that return true;
is still open lives past the basic block, so it can't be renamed. */
return closed_chains;
} }
/* Perform register renaming on the current function. */ /* Perform register renaming on the current function. */
...@@ -1353,44 +1771,20 @@ build_def_use (basic_block bb) ...@@ -1353,44 +1771,20 @@ build_def_use (basic_block bb)
static unsigned int static unsigned int
regrename_optimize (void) regrename_optimize (void)
{ {
basic_block bb;
char *first_obj;
df_set_flags (DF_LR_RUN_DCE); df_set_flags (DF_LR_RUN_DCE);
df_note_add_problem (); df_note_add_problem ();
df_analyze (); df_analyze ();
df_set_flags (DF_DEFER_INSN_RESCAN); df_set_flags (DF_DEFER_INSN_RESCAN);
memset (tick, 0, sizeof tick);
gcc_obstack_init (&rename_obstack); gcc_obstack_init (&rename_obstack);
first_obj = XOBNEWVAR (&rename_obstack, char, 0);
FOR_EACH_BB (bb) regrename_analyze ();
{
struct du_head *all_chains = 0;
id_to_chain = VEC_alloc (du_head_p, heap, 0); rename_chains ();
if (dump_file)
fprintf (dump_file, "\nBasic block %d:\n", bb->index);
all_chains = build_def_use (bb);
if (dump_file)
dump_def_use_chain (all_chains);
rename_chains (all_chains);
free_chain_data ();
obstack_free (&rename_obstack, first_obj);
}
free_chain_data ();
obstack_free (&rename_obstack, NULL); obstack_free (&rename_obstack, NULL);
if (dump_file)
fputc ('\n', dump_file);
return 0; return 0;
} }
......
...@@ -397,4 +397,48 @@ overlaps_hard_reg_set_p (const HARD_REG_SET regs, enum machine_mode mode, ...@@ -397,4 +397,48 @@ overlaps_hard_reg_set_p (const HARD_REG_SET regs, enum machine_mode mode,
return false; return false;
} }
/* Like add_to_hard_reg_set, but use a REGNO/NREGS range instead of
REGNO and MODE. */
static inline void
add_range_to_hard_reg_set (HARD_REG_SET *regs, unsigned int regno,
int nregs)
{
while (nregs-- > 0)
SET_HARD_REG_BIT (*regs, regno + nregs);
}
/* Likewise, but remove the registers. */
static inline void
remove_range_from_hard_reg_set (HARD_REG_SET *regs, unsigned int regno,
int nregs)
{
while (nregs-- > 0)
CLEAR_HARD_REG_BIT (*regs, regno + nregs);
}
/* Like overlaps_hard_reg_set_p, but use a REGNO/NREGS range instead of
REGNO and MODE. */
static inline bool
range_overlaps_hard_reg_set_p (const HARD_REG_SET set, unsigned regno,
int nregs)
{
while (nregs-- > 0)
if (TEST_HARD_REG_BIT (set, regno + nregs))
return true;
return false;
}
/* Like in_hard_reg_set_p, but use a REGNO/NREGS range instead of
REGNO and MODE. */
static inline bool
range_in_hard_reg_set_p (const HARD_REG_SET set, unsigned regno, int nregs)
{
while (nregs-- > 0)
if (!TEST_HARD_REG_BIT (set, regno + nregs))
return false;
return true;
}
#endif /* GCC_REGS_H */ #endif /* GCC_REGS_H */
...@@ -195,6 +195,11 @@ along with GCC; see the file COPYING3. If not see ...@@ -195,6 +195,11 @@ along with GCC; see the file COPYING3. If not see
#define FOR_EACH_VEC_ELT(T, V, I, P) \ #define FOR_EACH_VEC_ELT(T, V, I, P) \
for (I = 0; VEC_iterate (T, (V), (I), (P)); ++(I)) for (I = 0; VEC_iterate (T, (V), (I), (P)); ++(I))
/* Likewise, but start from FROM rather than 0. */
#define FOR_EACH_VEC_ELT_FROM(T, V, I, P, FROM) \
for (I = (FROM); VEC_iterate (T, (V), (I), (P)); ++(I))
/* Convenience macro for reverse iteration. */ /* Convenience macro for reverse iteration. */
#define FOR_EACH_VEC_ELT_REVERSE(T,V,I,P) \ #define FOR_EACH_VEC_ELT_REVERSE(T,V,I,P) \
......
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