df.c (df_bitmaps_free): Only work for bbs for that structures are allocated.

* df.c (df_bitmaps_free): Only work for bbs for that structures are
	allocated.
	(df_bb_modify): Realloc tables to the new index.
	(df_find_use): New function.
	(df_find_def, df_reg_used): Handle subregs.
	* df.h (df_find_use): Declare.

	* loop-invariant.c: Include hashtab.h.
	(struct invariant): Remove processed field, add eqto and reg fields.
	(struct invariant_expr_entry): New.
	(invariant_for_use, hash_invariant_expr_1, invariant_expr_equal_p,
	hash_invariant_expr, eq_invariant_expr, find_or_insert_inv,
	find_identical_invariants, merge_identical_invariants): New functions.
	(create_new_invariant): Return the new invariant.  Initialize new
	fields.
	(find_invariants): Call merge_identical_invariants.
	(get_inv_cost, best_gain_for_invariant, set_move_mark,
	move_invariant_reg): Handle equivalent invariants.
	* Makefile.in (loop-invariant.o): Add HASHTAB_H dependency.


Co-Authored-By: Steven Bosscher <stevenb@suse.de>

From-SVN: r108949
This commit is contained in:
Zdenek Dvorak 2005-12-22 15:23:40 +01:00 committed by Zdenek Dvorak
parent ab84748af1
commit 1052bd544e
5 changed files with 437 additions and 79 deletions

View File

@ -1,3 +1,26 @@
2005-12-22 Zdenek Dvorak <dvorakz@suse.cz>
Steven Bosscher <stevenb@suse.de>
* df.c (df_bitmaps_free): Only work for bbs for that structures are
allocated.
(df_bb_modify): Realloc tables to the new index.
(df_find_use): New function.
(df_find_def, df_reg_used): Handle subregs.
* df.h (df_find_use): Declare.
* loop-invariant.c: Include hashtab.h.
(struct invariant): Remove processed field, add eqto and reg fields.
(struct invariant_expr_entry): New.
(invariant_for_use, hash_invariant_expr_1, invariant_expr_equal_p,
hash_invariant_expr, eq_invariant_expr, find_or_insert_inv,
find_identical_invariants, merge_identical_invariants): New functions.
(create_new_invariant): Return the new invariant. Initialize new
fields.
(find_invariants): Call merge_identical_invariants.
(get_inv_cost, best_gain_for_invariant, set_move_mark,
move_invariant_reg): Handle equivalent invariants.
* Makefile.in (loop-invariant.o): Add HASHTAB_H dependency.
2005-12-22 Volker Reichelt <reichelt@igpm.rwth-aachen.de>
PR c++/23333

View File

@ -2372,7 +2372,8 @@ loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
output.h intl.h
loop-invariant.o : loop-invariant.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h \
$(TM_H) $(TM_P_H) function.h $(FLAGS_H) $(DF_H) $(OBSTACK_H) output.h
$(TM_H) $(TM_P_H) function.h $(FLAGS_H) $(DF_H) $(OBSTACK_H) output.h \
$(HASHTAB_H)
cfgloopmanip.o : cfgloopmanip.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) output.h \
coretypes.h $(TM_H) cfghooks.h $(OBSTACK_H)

View File

@ -451,14 +451,11 @@ df_bitmaps_alloc (struct df *df, bitmap blocks, int flags)
static void
df_bitmaps_free (struct df *df, int flags)
{
basic_block bb;
unsigned i;
FOR_EACH_BB (bb)
for (i = 0; i < df->n_bbs; i++)
{
struct bb_info *bb_info = DF_BB_INFO (df, bb);
if (!bb_info)
continue;
struct bb_info *bb_info = &df->bbs[i];
if ((flags & DF_RD) && bb_info->rd_in)
{
@ -2636,7 +2633,7 @@ static void
df_bb_modify (struct df *df, basic_block bb)
{
if ((unsigned) bb->index >= df->n_bbs)
df_bb_table_realloc (df, df->n_bbs);
df_bb_table_realloc (df, bb->index);
bitmap_set_bit (df->bbs_modified, bb->index);
}
@ -3032,25 +3029,42 @@ df_find_def (struct df *df, rtx insn, rtx reg)
{
struct df_link *defs;
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
gcc_assert (REG_P (reg));
for (defs = DF_INSN_DEFS (df, insn); defs; defs = defs->next)
if (rtx_equal_p (DF_REF_REG (defs->ref), reg))
if (rtx_equal_p (DF_REF_REAL_REG (defs->ref), reg))
return defs->ref;
return NULL;
}
/* Finds the reference corresponding to the use of REG in INSN.
DF is the dataflow object. */
struct ref *
df_find_use (struct df *df, rtx insn, rtx reg)
{
struct df_link *uses;
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
gcc_assert (REG_P (reg));
for (uses = DF_INSN_USES (df, insn); uses; uses = uses->next)
if (rtx_equal_p (DF_REF_REAL_REG (uses->ref), reg))
return uses->ref;
return NULL;
}
/* Return 1 if REG is referenced in INSN, zero otherwise. */
int
df_reg_used (struct df *df, rtx insn, rtx reg)
{
struct df_link *uses;
for (uses = DF_INSN_USES (df, insn); uses; uses = uses->next)
if (rtx_equal_p (DF_REF_REG (uses->ref), reg))
return 1;
return 0;
return df_find_use (df, insn, reg) != NULL;
}
static int

View File

@ -290,6 +290,8 @@ extern struct ref *df_bb_regno_last_def_find (struct df *, basic_block, unsigned
extern struct ref *df_find_def (struct df *, rtx, rtx);
extern struct ref *df_find_use (struct df *, rtx, rtx);
extern int df_reg_used (struct df *, rtx, rtx);
/* Functions for debugging from GDB. */

View File

@ -46,10 +46,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "basic-block.h"
#include "cfgloop.h"
#include "expr.h"
#include "recog.h"
#include "output.h"
#include "function.h"
#include "flags.h"
#include "df.h"
#include "hashtab.h"
/* The data stored for the loop. */
@ -88,8 +90,12 @@ struct invariant
/* The number of the invariant. */
unsigned invno;
/* Whether we already processed the invariant. */
bool processed;
/* The number of the invariant with the same value. */
unsigned eqto;
/* If we moved the invariant out of the loop, the register that contains its
value. */
rtx reg;
/* The definition of the invariant. */
struct def *def;
@ -114,6 +120,23 @@ struct invariant
unsigned stamp;
};
/* Entry for hash table of invariant expressions. */
struct invariant_expr_entry
{
/* The invariant. */
struct invariant *inv;
/* Its value. */
rtx expr;
/* Its mode. */
enum machine_mode mode;
/* Its hash. */
hashval_t hash;
};
/* The actual stamp for marking already visited invariants during determining
costs of movements. */
@ -199,6 +222,269 @@ check_maybe_invariant (rtx x)
return true;
}
/* Returns the invariant definition for USE, or NULL if USE is not
invariant. */
static struct invariant *
invariant_for_use (struct ref *use)
{
struct df_link *defs;
struct ref *def;
basic_block bb = BLOCK_FOR_INSN (use->insn), def_bb;
defs = DF_REF_CHAIN (use);
if (!defs || defs->next)
return NULL;
def = defs->ref;
if (!DF_REF_DATA (def))
return NULL;
def_bb = DF_REF_BB (def);
if (!dominated_by_p (CDI_DOMINATORS, bb, def_bb))
return NULL;
return DF_REF_DATA (def);
}
/* Computes hash value for invariant expression X in INSN. */
static hashval_t
hash_invariant_expr_1 (rtx insn, rtx x)
{
enum rtx_code code = GET_CODE (x);
int i, j;
const char *fmt;
hashval_t val = code;
int do_not_record_p;
struct ref *use;
struct invariant *inv;
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CONST:
case LABEL_REF:
return hash_rtx (x, GET_MODE (x), &do_not_record_p, NULL, false);
case REG:
use = df_find_use (df, insn, x);
if (!use)
return hash_rtx (x, GET_MODE (x), &do_not_record_p, NULL, false);
inv = invariant_for_use (use);
if (!inv)
return hash_rtx (x, GET_MODE (x), &do_not_record_p, NULL, false);
gcc_assert (inv->eqto != ~0u);
return inv->eqto;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
val ^= hash_invariant_expr_1 (insn, XEXP (x, i));
else if (fmt[i] == 'E')
{
for (j = 0; j < XVECLEN (x, i); j++)
val ^= hash_invariant_expr_1 (insn, XVECEXP (x, i, j));
}
}
return val;
}
/* Returns true if the invariant expressions E1 and E2 used in insns INSN1
and INSN2 have always the same value. */
static bool
invariant_expr_equal_p (rtx insn1, rtx e1, rtx insn2, rtx e2)
{
enum rtx_code code = GET_CODE (e1);
int i, j;
const char *fmt;
struct ref *use1, *use2;
struct invariant *inv1 = NULL, *inv2 = NULL;
rtx sub1, sub2;
/* If mode of only one of the operands is VOIDmode, it is not equivalent to
the other one. If both are VOIDmode, we rely on the caller of this
function to verify that their modes are the same. */
if (code != GET_CODE (e2) || GET_MODE (e1) != GET_MODE (e2))
return false;
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CONST:
case LABEL_REF:
return rtx_equal_p (e1, e2);
case REG:
use1 = df_find_use (df, insn1, e1);
use2 = df_find_use (df, insn2, e2);
if (use1)
inv1 = invariant_for_use (use1);
if (use2)
inv2 = invariant_for_use (use2);
if (!inv1 && !inv2)
return rtx_equal_p (e1, e2);
if (!inv1 || !inv2)
return false;
gcc_assert (inv1->eqto != ~0u);
gcc_assert (inv2->eqto != ~0u);
return inv1->eqto == inv2->eqto;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
sub1 = XEXP (e1, i);
sub2 = XEXP (e2, i);
if (!invariant_expr_equal_p (insn1, sub1, insn2, sub2))
return false;
}
else if (fmt[i] == 'E')
{
if (XVECLEN (e1, i) != XVECLEN (e2, i))
return false;
for (j = 0; j < XVECLEN (e1, i); j++)
{
sub1 = XVECEXP (e1, i, j);
sub2 = XVECEXP (e2, i, j);
if (!invariant_expr_equal_p (insn1, sub1, insn2, sub2))
return false;
}
}
}
return true;
}
/* Returns hash value for invariant expression entry E. */
static hashval_t
hash_invariant_expr (const void *e)
{
const struct invariant_expr_entry *entry = e;
return entry->hash;
}
/* Compares invariant expression entries E1 and E2. */
static int
eq_invariant_expr (const void *e1, const void *e2)
{
const struct invariant_expr_entry *entry1 = e1;
const struct invariant_expr_entry *entry2 = e2;
if (entry1->mode != entry2->mode)
return 0;
return invariant_expr_equal_p (entry1->inv->insn, entry1->expr,
entry2->inv->insn, entry2->expr);
}
/* Checks whether invariant with value EXPR in machine mode MODE is
recorded in EQ. If this is the case, return the invariant. Otherwise
insert INV to the table for this expression and return INV. */
static struct invariant *
find_or_insert_inv (htab_t eq, rtx expr, enum machine_mode mode,
struct invariant *inv)
{
hashval_t hash = hash_invariant_expr_1 (inv->insn, expr);
struct invariant_expr_entry *entry;
struct invariant_expr_entry pentry;
PTR *slot;
pentry.expr = expr;
pentry.inv = inv;
pentry.mode = mode;
slot = htab_find_slot_with_hash (eq, &pentry, hash, INSERT);
entry = *slot;
if (entry)
return entry->inv;
entry = xmalloc (sizeof (struct invariant_expr_entry));
entry->inv = inv;
entry->expr = expr;
entry->mode = mode;
entry->hash = hash;
*slot = entry;
return inv;
}
/* Finds invariants identical to INV and records the equivalence. EQ is the
hash table of the invariants. */
static void
find_identical_invariants (htab_t eq, struct invariant *inv)
{
unsigned depno;
bitmap_iterator bi;
struct invariant *dep;
rtx expr, set;
enum machine_mode mode;
if (inv->eqto != ~0u)
return;
EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, depno, bi)
{
dep = VEC_index (invariant_p, invariants, depno);
find_identical_invariants (eq, dep);
}
set = single_set (inv->insn);
expr = SET_SRC (set);
mode = GET_MODE (expr);
if (mode == VOIDmode)
mode = GET_MODE (SET_DEST (set));
inv->eqto = find_or_insert_inv (eq, expr, mode, inv)->invno;
if (dump_file && inv->eqto != inv->invno)
fprintf (dump_file,
"Invariant %d is equivalent to invariant %d.\n ",
inv->invno, inv->eqto);
}
/* Find invariants with the same value and record the equivalences. */
static void
merge_identical_invariants (void)
{
unsigned i;
struct invariant *inv;
htab_t eq = htab_create (VEC_length (invariant_p, invariants),
hash_invariant_expr, eq_invariant_expr, free);
for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++)
find_identical_invariants (eq, inv);
htab_delete (eq);
}
/* Determines the basic blocks inside LOOP that are always executed and
stores their bitmap to ALWAYS_REACHED. MAY_EXIT is a bitmap of
basic blocks that may either exit the loop, or contain the call that
@ -320,9 +606,10 @@ find_defs (struct loop *loop, basic_block *body)
/* Creates a new invariant for definition DEF in INSN, depending on invariants
in DEPENDS_ON. ALWAYS_EXECUTED is true if the insn is always executed,
unless the program ends due to a function call. */
unless the program ends due to a function call. The newly created invariant
is returned. */
static void
static struct invariant *
create_new_invariant (struct def *def, rtx insn, bitmap depends_on,
bool always_executed)
{
@ -341,11 +628,12 @@ create_new_invariant (struct def *def, rtx insn, bitmap depends_on,
inv->cost = rtx_cost (SET_SRC (set), SET);
inv->move = false;
inv->processed = false;
inv->reg = NULL_RTX;
inv->stamp = 0;
inv->insn = insn;
inv->invno = VEC_length (invariant_p, invariants);
inv->eqto = ~0u;
if (def)
def->invno = inv->invno;
VEC_safe_push (invariant_p, heap, invariants, inv);
@ -357,6 +645,8 @@ create_new_invariant (struct def *def, rtx insn, bitmap depends_on,
INSN_UID (insn), inv->invno, inv->cost);
dump_bitmap (dump_file, inv->depends_on);
}
return inv;
}
/* Record USE at DEF. */
@ -387,7 +677,8 @@ check_dependencies (rtx insn, bitmap depends_on)
struct ref *use, *def;
basic_block bb = BLOCK_FOR_INSN (insn), def_bb;
struct def *def_data;
struct invariant *inv;
for (uses = DF_INSN_USES (df, insn); uses; uses = uses->next)
{
use = uses->ref;
@ -400,11 +691,17 @@ check_dependencies (rtx insn, bitmap depends_on)
return false;
def = defs->ref;
def_data = DF_REF_DATA (def);
if (!def_data)
inv = DF_REF_DATA (def);
if (!inv)
return false;
def_data = inv->def;
gcc_assert (def_data != NULL);
def_bb = DF_REF_BB (def);
/* Note that in case bb == def_bb, we know that the definition dominates
insn, because def has DF_REF_DATA defined and we process the insns
in the basic block bb sequentially. */
if (!dominated_by_p (CDI_DOMINATORS, bb, def_bb))
return false;
@ -426,13 +723,14 @@ find_invariant_insn (rtx insn, bool always_reached, bool always_executed)
bitmap depends_on;
rtx set, dest;
bool simple = true;
struct invariant *inv;
/* Until we get rid of LIBCALLS. */
if (find_reg_note (insn, REG_RETVAL, NULL_RTX)
|| find_reg_note (insn, REG_LIBCALL, NULL_RTX)
|| find_reg_note (insn, REG_NO_CONFLICT, NULL_RTX))
return;
set = single_set (insn);
if (!set)
return;
@ -465,15 +763,17 @@ find_invariant_insn (rtx insn, bool always_reached, bool always_executed)
}
if (simple)
{
ref = df_find_def (df, insn, dest);
def = xcalloc (1, sizeof (struct def));
DF_REF_DATA (ref) = def;
}
def = xcalloc (1, sizeof (struct def));
else
def = NULL;
create_new_invariant (def, insn, depends_on, always_executed);
inv = create_new_invariant (def, insn, depends_on, always_executed);
if (simple)
{
ref = df_find_def (df, insn, dest);
DF_REF_DATA (ref) = inv;
}
}
/* Record registers used in INSN that have a unique invariant definition. */
@ -481,26 +781,16 @@ find_invariant_insn (rtx insn, bool always_reached, bool always_executed)
static void
record_uses (rtx insn)
{
struct df_link *uses, *defs;
struct ref *use, *def;
basic_block bb = BLOCK_FOR_INSN (insn), def_bb;
struct df_link *uses;
struct ref *use;
struct invariant *inv;
for (uses = DF_INSN_USES (df, insn); uses; uses = uses->next)
{
use = uses->ref;
defs = DF_REF_CHAIN (use);
if (!defs || defs->next)
continue;
def = defs->ref;
if (!DF_REF_DATA (def))
continue;
def_bb = DF_REF_BB (def);
if (!dominated_by_p (CDI_DOMINATORS, bb, def_bb))
continue;
record_use (DF_REF_DATA (def), DF_REF_LOC (use), DF_REF_INSN (use));
inv = invariant_for_use (use);
if (inv)
record_use (inv->def, DF_REF_LOC (use), DF_REF_INSN (use));
}
}
@ -573,6 +863,7 @@ find_invariants (struct loop *loop)
find_defs (loop, body);
find_invariants_body (loop, body, always_reached, always_executed);
merge_identical_invariants ();
BITMAP_FREE (always_reached);
BITMAP_FREE (always_executed);
@ -607,6 +898,9 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed)
struct invariant *dep;
bitmap_iterator bi;
/* Find the representative of the class of the equivalent invariants. */
inv = VEC_index (invariant_p, invariants, inv->eqto);
*comp_cost = 0;
*regs_needed = 0;
if (inv->move
@ -683,6 +977,10 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed,
if (inv->move)
continue;
/* Only consider the "representatives" of equivalent invariants. */
if (inv->eqto != inv->invno)
continue;
again = gain_for_invariant (inv, &aregs_needed,
new_regs, regs_used, n_inv_uses);
if (again > gain)
@ -704,6 +1002,9 @@ set_move_mark (unsigned invno)
struct invariant *inv = VEC_index (invariant_p, invariants, invno);
bitmap_iterator bi;
/* Find the representative of the class of the equivalent invariants. */
inv = VEC_index (invariant_p, invariants, inv->eqto);
if (inv->move)
return;
inv->move = true;
@ -766,50 +1067,68 @@ static void
move_invariant_reg (struct loop *loop, unsigned invno)
{
struct invariant *inv = VEC_index (invariant_p, invariants, invno);
struct invariant *repr = VEC_index (invariant_p, invariants, inv->eqto);
unsigned i;
basic_block preheader = loop_preheader_edge (loop)->src;
rtx reg, set;
struct use *use;
bitmap_iterator bi;
if (inv->processed)
if (inv->reg
|| !repr->move)
return;
inv->processed = true;
if (inv->depends_on)
/* If this is a representative of the class of equivalent invariants,
really move the invariant. Otherwise just replace its use with
the register used for the representative. */
if (inv == repr)
{
EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, i, bi)
if (inv->depends_on)
{
move_invariant_reg (loop, i);
EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, i, bi)
{
move_invariant_reg (loop, i);
}
}
}
/* Move the set out of the loop. If the set is always executed (we could
omit this condition if we know that the register is unused outside of the
loop, but it does not seem worth finding out) and it has no uses that
would not be dominated by it, we may just move it (TODO). Otherwise we
need to create a temporary register. */
set = single_set (inv->insn);
reg = gen_reg_rtx (GET_MODE (SET_DEST (set)));
df_pattern_emit_after (df, gen_move_insn (SET_DEST (set), reg),
BLOCK_FOR_INSN (inv->insn), inv->insn);
/* Move the set out of the loop. If the set is always executed (we could
omit this condition if we know that the register is unused outside of the
loop, but it does not seem worth finding out) and it has no uses that
would not be dominated by it, we may just move it (TODO). Otherwise we
need to create a temporary register. */
set = single_set (inv->insn);
reg = gen_reg_rtx (GET_MODE (SET_DEST (set)));
df_pattern_emit_after (df, gen_move_insn (SET_DEST (set), reg),
BLOCK_FOR_INSN (inv->insn), inv->insn);
/* If the SET_DEST of the invariant insn is a reg, we can just move
the insn out of the loop. Otherwise, we have to use gen_move_insn
to let emit_move_insn produce a valid instruction stream. */
if (REG_P (SET_DEST (set)))
{
SET_DEST (set) = reg;
reorder_insns (inv->insn, inv->insn, BB_END (preheader));
df_insn_modify (df, preheader, inv->insn);
/* If the SET_DEST of the invariant insn is a reg, we can just move
the insn out of the loop. Otherwise, we have to use gen_move_insn
to let emit_move_insn produce a valid instruction stream. */
if (REG_P (SET_DEST (set)))
{
SET_DEST (set) = reg;
reorder_insns (inv->insn, inv->insn, BB_END (preheader));
df_insn_modify (df, preheader, inv->insn);
}
else
{
df_pattern_emit_after (df, gen_move_insn (reg, SET_SRC (set)),
preheader, BB_END (preheader));
df_insn_delete (df, BLOCK_FOR_INSN (inv->insn), inv->insn);
}
}
else
{
df_pattern_emit_after (df, gen_move_insn (reg, SET_SRC (set)),
preheader, BB_END (preheader));
move_invariant_reg (loop, repr->invno);
reg = repr->reg;
set = single_set (inv->insn);
df_pattern_emit_after (df, gen_move_insn (SET_DEST (set), reg),
BLOCK_FOR_INSN (inv->insn), inv->insn);
df_insn_delete (df, BLOCK_FOR_INSN (inv->insn), inv->insn);
}
inv->reg = reg;
/* Replace the uses we know to be dominated. It saves work for copy
propagation, and also it is necessary so that dependent invariants
are computed right. */
@ -833,10 +1152,7 @@ move_invariants (struct loop *loop)
unsigned i;
for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++)
{
if (inv->move)
move_invariant_reg (loop, i);
}
move_invariant_reg (loop, i);
}
/* Initializes invariant motion data. */
@ -863,9 +1179,11 @@ free_inv_motion_data (void)
if (!df->defs[i])
continue;
def = DF_REF_DATA (df->defs[i]);
if (!def)
inv = DF_REF_DATA (df->defs[i]);
if (!inv)
continue;
def = inv->def;
gcc_assert (def != NULL);
free_use_list (def->uses);
free (def);