Commit 03fd2215 by Zdenek Dvorak Committed by Zdenek Dvorak

loop-iv.c: Include df.h and hashtab.h.

	* loop-iv.c: Include df.h and hashtab.h.
	(enum iv_grd_result): New enum.
	(DF_REF_IV, DF_REF_IV_SET): New macros.
	(struct biv_entry): New.
	(df, bivs): New global variables.
	(struct insn_info, insn_info, last_def, bivs, max_insn_no, max_reg_no,
	assign_luids, mark_sets, kill_sets, mark_single_set, simple_set_p):
	Removed.
	(clear_iv_info, latch_dominating_def, record_iv, iv_analyze_expr,
	iv_analyze_result, iv_analyze_def, biv_hash, biv_eq,
	analyzed_for_bivness_p, record_biv): New functions.
	(iv_analysis_loop_init, iv_get_reaching_def, simple_reg_p,
	get_biv_step_1, get_biv_step, iv_analyze_biv, iv_analyze_op,
	iv_analyze, biv_p, iv_analysis_done): Work with df representation of
	UD chains.
	(iv_constant, iv_subreg, iv_extend, iv_mult, iv_shift): Do not set
	analysed.
	(iv_number_of_iterations): Use new interface to iv analysis.
	* loop-unroll.c: Do not include varray.h.
	(analyze_iv_to_split_insn): Use new interface to iv
	analysis.
	* loop-unswitch.c (may_unswitch_on): Ditto.
	* 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.h (df_find_use): Declare.
	* optabs.c (expand_unop): Make the mode of the REG_EQUAL node be
	outmode.
	* cfgloop.h (struct rtx_iv): Remove analysed field.
	(iv_get_reaching_def): Removed.
	(iv_analyze_result, iv_analyze_expr, iv_current_loop_df): Declare.
	* Makefile.in (loop-unroll.o): Remove VARRAY_H dependency.
	(loop-iv.o): Add df.h and hashtab.h dependency.
	* df-problems.c (df_ru_alloc, df_rd_alloc): Fix memory reallocation.

From-SVN: r110005
parent b04c9063
2006-01-20 Zdenek Dvorak <dvorakz@suse.cz>
* loop-iv.c: Include df.h and hashtab.h.
(enum iv_grd_result): New enum.
(DF_REF_IV, DF_REF_IV_SET): New macros.
(struct biv_entry): New.
(df, bivs): New global variables.
(struct insn_info, insn_info, last_def, bivs, max_insn_no, max_reg_no,
assign_luids, mark_sets, kill_sets, mark_single_set, simple_set_p):
Removed.
(clear_iv_info, latch_dominating_def, record_iv, iv_analyze_expr,
iv_analyze_result, iv_analyze_def, biv_hash, biv_eq,
analyzed_for_bivness_p, record_biv): New functions.
(iv_analysis_loop_init, iv_get_reaching_def, simple_reg_p,
get_biv_step_1, get_biv_step, iv_analyze_biv, iv_analyze_op,
iv_analyze, biv_p, iv_analysis_done): Work with df representation of
UD chains.
(iv_constant, iv_subreg, iv_extend, iv_mult, iv_shift): Do not set
analysed.
(iv_number_of_iterations): Use new interface to iv analysis.
* loop-unroll.c: Do not include varray.h.
(analyze_iv_to_split_insn): Use new interface to iv
analysis.
* loop-unswitch.c (may_unswitch_on): Ditto.
* 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.h (df_find_use): Declare.
* optabs.c (expand_unop): Make the mode of the REG_EQUAL node be
outmode.
* cfgloop.h (struct rtx_iv): Remove analysed field.
(iv_get_reaching_def): Removed.
(iv_analyze_result, iv_analyze_expr, iv_current_loop_df): Declare.
* Makefile.in (loop-unroll.o): Remove VARRAY_H dependency.
(loop-iv.o): Add df.h and hashtab.h dependency.
* df-problems.c (df_ru_alloc, df_rd_alloc): Fix memory reallocation.
2006-01-20 Alan Modra <amodra@bigpond.net.au> 2006-01-20 Alan Modra <amodra@bigpond.net.au>
* libgcc2.c (__floatdisf, __floatdidf): Don't use IBM Extended * libgcc2.c (__floatdisf, __floatdidf): Don't use IBM Extended
......
...@@ -2431,7 +2431,7 @@ struct-equiv.o : struct-equiv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ ...@@ -2431,7 +2431,7 @@ struct-equiv.o : struct-equiv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(REGS_H) $(EMIT_RTL_H) $(REGS_H) $(EMIT_RTL_H)
loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \ loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \
hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \ hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \
output.h intl.h output.h intl.h $(DF_H) $(HASHTAB_H)
loop-invariant.o : loop-invariant.c $(CONFIG_H) $(SYSTEM_H) $(RTL_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 \ $(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 \
...@@ -2447,7 +2447,7 @@ loop-unswitch.o : loop-unswitch.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \ ...@@ -2447,7 +2447,7 @@ loop-unswitch.o : loop-unswitch.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \
output.h $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) output.h $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H)
loop-unroll.o: loop-unroll.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \ loop-unroll.o: loop-unroll.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TM_H) \
$(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) $(PARAMS_H) \ $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) $(PARAMS_H) \
output.h $(EXPR_H) coretypes.h $(TM_H) $(HASHTAB_H) $(RECOG_H) $(VARRAY_H) \ output.h $(EXPR_H) coretypes.h $(TM_H) $(HASHTAB_H) $(RECOG_H) \
$(OBSTACK_H) $(OBSTACK_H)
dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h $(OBSTACK_H) toplev.h hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h $(OBSTACK_H) toplev.h
......
...@@ -352,9 +352,6 @@ struct rtx_iv ...@@ -352,9 +352,6 @@ struct rtx_iv
/* The mode the variable iterates in. */ /* The mode the variable iterates in. */
enum machine_mode mode; enum machine_mode mode;
/* Whether we have already filled the remaining fields. */
unsigned analysed : 1;
/* Whether the first iteration needs to be handled specially. */ /* Whether the first iteration needs to be handled specially. */
unsigned first_special : 1; unsigned first_special : 1;
}; };
...@@ -404,12 +401,14 @@ struct niter_desc ...@@ -404,12 +401,14 @@ struct niter_desc
}; };
extern void iv_analysis_loop_init (struct loop *); extern void iv_analysis_loop_init (struct loop *);
extern rtx iv_get_reaching_def (rtx, rtx);
extern bool iv_analyze (rtx, rtx, struct rtx_iv *); extern bool iv_analyze (rtx, rtx, struct rtx_iv *);
extern bool iv_analyze_result (rtx, rtx, struct rtx_iv *);
extern bool iv_analyze_expr (rtx, rtx, enum machine_mode, struct rtx_iv *);
extern rtx get_iv_value (struct rtx_iv *, rtx); extern rtx get_iv_value (struct rtx_iv *, rtx);
extern bool biv_p (rtx, rtx); extern bool biv_p (rtx, rtx);
extern void find_simple_exit (struct loop *, struct niter_desc *); extern void find_simple_exit (struct loop *, struct niter_desc *);
extern void iv_analysis_done (void); extern void iv_analysis_done (void);
extern struct df *iv_current_loop_df (void);
extern struct niter_desc *get_simple_loop_desc (struct loop *loop); extern struct niter_desc *get_simple_loop_desc (struct loop *loop);
extern void free_simple_loop_desc (struct loop *loop); extern void free_simple_loop_desc (struct loop *loop);
......
...@@ -369,12 +369,12 @@ df_ru_alloc (struct dataflow *dflow, bitmap blocks_to_rescan) ...@@ -369,12 +369,12 @@ df_ru_alloc (struct dataflow *dflow, bitmap blocks_to_rescan)
} }
} }
if (problem_data->use_sites_size > reg_size) if (problem_data->use_sites_size < reg_size)
{ {
problem_data->use_sites problem_data->use_sites
= xrealloc (problem_data->use_sites, reg_size *sizeof (bitmap)); = xrealloc (problem_data->use_sites, reg_size * sizeof (bitmap));
memset (problem_data->use_sites, 0, memset (problem_data->use_sites + problem_data->use_sites_size, 0,
(reg_size - problem_data->use_sites_size) *sizeof (bitmap)); (reg_size - problem_data->use_sites_size) * sizeof (bitmap));
problem_data->use_sites_size = reg_size; problem_data->use_sites_size = reg_size;
} }
...@@ -876,11 +876,11 @@ df_rd_alloc (struct dataflow *dflow, bitmap blocks_to_rescan) ...@@ -876,11 +876,11 @@ df_rd_alloc (struct dataflow *dflow, bitmap blocks_to_rescan)
} }
} }
if (problem_data->def_sites_size > reg_size) if (problem_data->def_sites_size < reg_size)
{ {
problem_data->def_sites problem_data->def_sites
= xrealloc (problem_data->def_sites, reg_size *sizeof (bitmap)); = xrealloc (problem_data->def_sites, reg_size *sizeof (bitmap));
memset (problem_data->def_sites, 0, memset (problem_data->def_sites + problem_data->def_sites_size, 0,
(reg_size - problem_data->def_sites_size) *sizeof (bitmap)); (reg_size - problem_data->def_sites_size) *sizeof (bitmap));
problem_data->def_sites_size = reg_size; problem_data->def_sites_size = reg_size;
} }
......
...@@ -18,34 +18,35 @@ along with GCC; see the file COPYING. If not, write to the Free ...@@ -18,34 +18,35 @@ along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */ 02110-1301, USA. */
/* This is just a very simplistic analysis of induction variables of the loop. /* This is a simple analysis of induction variables of the loop. The major use
The major use is for determining the number of iterations of a loop for is for determining the number of iterations of a loop for loop unrolling,
loop unrolling, doloop optimization and branch prediction. For this we doloop optimization and branch prediction. The iv information is computed
are only interested in bivs and a fairly limited set of givs that are on demand.
needed in the exit condition. We also only compute the iv information on
demand. Induction variable is analyzed by walking the use-def chains. When a biv
is found, it is cached in the bivs hash table. When register is proved
The interesting registers are determined. A register is interesting if to be a giv, its description is stored to DF_REF_DATA of the def reference.
-- it is set only in the blocks that dominate the latch of the current loop The analysis works always with one loop -- you must call
-- all its sets are simple -- i.e. in the form we understand iv_analysis_loop_init (loop) for it. All the other functions then work with
this loop. When you need to work with another loop, just call
We also number the insns sequentially in each basic block. For a use of the iv_analysis_loop_init for it. When you no longer need iv analysis, call
interesting reg, it is now easy to find a reaching definition (there may be iv_analysis_done () to clean up the memory.
only one).
The available functions are:
Induction variable is then simply analyzed by walking the use-def
chains. iv_analyze (insn, reg, iv): Stores the description of the induction variable
corresponding to the use of register REG in INSN to IV. Returns true if
Usage: REG is an induction variable in INSN. false otherwise.
If use of REG is not found in INSN, following insns are scanned (so that
iv_analysis_loop_init (loop); we may call this function on insn returned by get_condition).
insn = iv_get_reaching_def (where, reg); iv_analyze_result (insn, def, iv): Stores to IV the description of the iv
if (iv_analyze (insn, reg, &iv)) corresponding to DEF, which is a register defined in INSN.
{ iv_analyze_expr (insn, rhs, mode, iv): Stores to IV the description of iv
... corresponding to expression EXPR evaluated at INSN. All registers used bu
} EXPR must also be used in INSN.
iv_analysis_done (); */ iv_current_loop_df (): Returns the dataflow object for the current loop used
by iv analysis. */
#include "config.h" #include "config.h"
#include "system.h" #include "system.h"
...@@ -60,40 +61,61 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ...@@ -60,40 +61,61 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "intl.h" #include "intl.h"
#include "output.h" #include "output.h"
#include "toplev.h" #include "toplev.h"
#include "df.h"
#include "hashtab.h"
/* The insn information. */ /* Possible return values of iv_get_reaching_def. */
struct insn_info enum iv_grd_result
{ {
/* Id of the insn. */ /* More than one reaching def, or reaching def that does not
unsigned luid; dominate the use. */
GRD_INVALID,
/* The previous definition of the register defined by the single /* The use is trivial invariant of the loop, i.e. is not changed
set in the insn. */ inside the loop. */
rtx prev_def; GRD_INVARIANT,
/* The description of the iv. */ /* The use is reached by initial value and a value from the
struct rtx_iv iv; previous iteration. */
GRD_MAYBE_BIV,
/* The use has single dominating def. */
GRD_SINGLE_DOM
};
/* Information about a biv. */
struct biv_entry
{
unsigned regno; /* The register of the biv. */
struct rtx_iv iv; /* Value of the biv. */
}; };
static struct insn_info *insn_info; /* Induction variable stored at the reference. */
#define DF_REF_IV(REF) ((struct rtx_iv *) DF_REF_DATA (REF))
#define DF_REF_IV_SET(REF, IV) DF_REF_DATA (REF) = (IV)
/* The last definition of register. */ /* The current loop. */
static rtx *last_def; static struct loop *current_loop;
/* The bivs. */ /* Dataflow information for the current loop. */
static struct rtx_iv *bivs; static struct df *df = NULL;
/* Maximal insn number for that there is place in insn_info array. */ /* Bivs of the current loop. */
static unsigned max_insn_no; static htab_t bivs;
/* Maximal register number for that there is place in bivs and last_def /* Return the dataflow object for the current loop. */
arrays. */ struct df *
iv_current_loop_df (void)
{
return df;
}
static unsigned max_reg_no; static bool iv_analyze_op (rtx, rtx, struct rtx_iv *);
/* Dumps information about IV to FILE. */ /* Dumps information about IV to FILE. */
...@@ -139,23 +161,6 @@ dump_iv_info (FILE *file, struct rtx_iv *iv) ...@@ -139,23 +161,6 @@ dump_iv_info (FILE *file, struct rtx_iv *iv)
fprintf (file, " (first special)"); fprintf (file, " (first special)");
} }
/* Assigns luids to insns in basic block BB. */
static void
assign_luids (basic_block bb)
{
unsigned i = 0, uid;
rtx insn;
FOR_BB_INSNS (bb, insn)
{
uid = INSN_UID (insn);
insn_info[uid].luid = i++;
insn_info[uid].prev_def = NULL_RTX;
insn_info[uid].iv.analysed = false;
}
}
/* Generates a subreg to get the least significant part of EXPR (in mode /* Generates a subreg to get the least significant part of EXPR (in mode
INNER_MODE) to OUTER_MODE. */ INNER_MODE) to OUTER_MODE. */
...@@ -191,131 +196,45 @@ simple_reg_p (rtx reg) ...@@ -191,131 +196,45 @@ simple_reg_p (rtx reg)
if (GET_MODE_CLASS (GET_MODE (reg)) != MODE_INT) if (GET_MODE_CLASS (GET_MODE (reg)) != MODE_INT)
return false; return false;
if (last_def[r] == const0_rtx)
return false;
return true; return true;
} }
/* Checks whether assignment LHS = RHS is simple enough for us to process. */ /* Clears the information about ivs stored in df. */
static bool static void
simple_set_p (rtx lhs, rtx rhs) clear_iv_info (void)
{ {
rtx op0, op1; unsigned i, n_defs = DF_DEFS_SIZE (df);
struct rtx_iv *iv;
if (!REG_P (lhs) struct df_ref *def;
|| !simple_reg_p (lhs))
return false;
if (CONSTANT_P (rhs))
return true;
switch (GET_CODE (rhs)) for (i = 0; i < n_defs; i++)
{ {
case SUBREG: def = DF_DEFS_GET (df, i);
case REG: iv = DF_REF_IV (def);
return simple_reg_p (rhs); if (!iv)
continue;
case SIGN_EXTEND: free (iv);
case ZERO_EXTEND: DF_REF_IV_SET (def, NULL);
case NEG:
return simple_reg_p (XEXP (rhs, 0));
case PLUS:
case MINUS:
case MULT:
case ASHIFT:
op0 = XEXP (rhs, 0);
op1 = XEXP (rhs, 1);
if (!simple_reg_p (op0)
&& !CONSTANT_P (op0))
return false;
if (!simple_reg_p (op1)
&& !CONSTANT_P (op1))
return false;
if (GET_CODE (rhs) == MULT
&& !CONSTANT_P (op0)
&& !CONSTANT_P (op1))
return false;
if (GET_CODE (rhs) == ASHIFT
&& CONSTANT_P (op0))
return false;
return true;
default:
return false;
} }
}
/* Mark single SET in INSN. */
static rtx htab_empty (bivs);
mark_single_set (rtx insn, rtx set)
{
rtx def = SET_DEST (set), src;
unsigned regno, uid;
src = find_reg_equal_equiv_note (insn);
if (src)
src = XEXP (src, 0);
else
src = SET_SRC (set);
if (!simple_set_p (SET_DEST (set), src))
return NULL_RTX;
regno = REGNO (def);
uid = INSN_UID (insn);
bivs[regno].analysed = false;
insn_info[uid].prev_def = last_def[regno];
last_def[regno] = insn;
return def;
} }
/* Invalidate register REG unless it is equal to EXCEPT. */ /* Returns hash value for biv B. */
static void static hashval_t
kill_sets (rtx reg, rtx by ATTRIBUTE_UNUSED, void *except) biv_hash (const void *b)
{ {
if (GET_CODE (reg) == SUBREG) return ((const struct biv_entry *) b)->regno;
reg = SUBREG_REG (reg);
if (!REG_P (reg))
return;
if (reg == except)
return;
last_def[REGNO (reg)] = const0_rtx;
} }
/* Marks sets in basic block BB. If DOM is true, BB dominates the loop /* Compares biv B and register R. */
latch. */
static void static int
mark_sets (basic_block bb, bool dom) biv_eq (const void *b, const void *r)
{ {
rtx insn, set, def; return ((const struct biv_entry *) b)->regno == REGNO ((rtx) r);
FOR_BB_INSNS (bb, insn)
{
if (!INSN_P (insn))
continue;
if (dom
&& (set = single_set (insn)))
def = mark_single_set (insn, set);
else
def = NULL_RTX;
note_stores (PATTERN (insn), kill_sets, def);
}
} }
/* Prepare the data for an induction variable analysis of a LOOP. */ /* Prepare the data for an induction variable analysis of a LOOP. */
...@@ -323,97 +242,116 @@ mark_sets (basic_block bb, bool dom) ...@@ -323,97 +242,116 @@ mark_sets (basic_block bb, bool dom)
void void
iv_analysis_loop_init (struct loop *loop) iv_analysis_loop_init (struct loop *loop)
{ {
basic_block *body = get_loop_body_in_dom_order (loop); basic_block *body = get_loop_body_in_dom_order (loop), bb;
unsigned b; bitmap blocks = BITMAP_ALLOC (NULL);
unsigned i;
bool first_time = (df == NULL);
if ((unsigned) get_max_uid () >= max_insn_no) current_loop = loop;
{
/* Add some reserve for insns and registers produced in optimizations. */
max_insn_no = get_max_uid () + 100;
if (insn_info)
free (insn_info);
insn_info = xmalloc (max_insn_no * sizeof (struct insn_info));
}
if ((unsigned) max_reg_num () >= max_reg_no) /* Clear the information from the analysis of the previous loop. */
if (first_time)
{ {
max_reg_no = max_reg_num () + 100; df = df_init (DF_HARD_REGS | DF_EQUIV_NOTES);
if (last_def) df_chain_add_problem (df, DF_UD_CHAIN);
free (last_def); bivs = htab_create (10, biv_hash, biv_eq, free);
last_def = xmalloc (max_reg_no * sizeof (rtx));
if (bivs)
free (bivs);
bivs = xmalloc (max_reg_no * sizeof (struct rtx_iv));
} }
else
clear_iv_info ();
memset (last_def, 0, max_reg_num () * sizeof (rtx)); for (i = 0; i < loop->num_nodes; i++)
for (b = 0; b < loop->num_nodes; b++)
{ {
assign_luids (body[b]); bb = body[i];
mark_sets (body[b], just_once_each_iteration_p (loop, body[b])); bitmap_set_bit (blocks, bb->index);
} }
df_set_blocks (df, blocks);
df_analyze (df);
BITMAP_FREE (blocks);
free (body); free (body);
} }
/* Gets definition of REG reaching the INSN. If REG is not simple, const0_rtx /* Finds the definition of REG that dominates loop latch and stores
is returned. If INSN is before the first def in the loop, NULL_RTX is it to DEF. Returns false if there is not a single definition
returned. */ dominating the latch. If REG has no definition in loop, DEF
is set to NULL and true is returned. */
rtx static bool
iv_get_reaching_def (rtx insn, rtx reg) latch_dominating_def (rtx reg, struct df_ref **def)
{ {
unsigned regno, luid, auid; struct df_ref *single_rd = NULL, *adef;
rtx ainsn; unsigned regno = REGNO (reg);
basic_block bb, abb; struct df_reg_info *reg_info = DF_REG_DEF_GET (df, regno);
struct df_rd_bb_info *bb_info = DF_RD_BB_INFO (df, current_loop->latch);
if (GET_CODE (reg) == SUBREG) for (adef = reg_info->reg_chain; adef; adef = adef->next_reg)
{ {
if (!subreg_lowpart_p (reg)) if (!bitmap_bit_p (bb_info->out, DF_REF_ID (adef)))
return const0_rtx; continue;
reg = SUBREG_REG (reg);
/* More than one reaching definition. */
if (single_rd)
return false;
if (!just_once_each_iteration_p (current_loop, DF_REF_BB (adef)))
return false;
single_rd = adef;
} }
if (!REG_P (reg))
return NULL_RTX;
regno = REGNO (reg); *def = single_rd;
if (!last_def[regno] return true;
|| last_def[regno] == const0_rtx) }
return last_def[regno];
bb = BLOCK_FOR_INSN (insn); /* Gets definition of REG reaching its use in INSN and stores it to DEF. */
luid = insn_info[INSN_UID (insn)].luid;
ainsn = last_def[regno]; static enum iv_grd_result
while (1) iv_get_reaching_def (rtx insn, rtx reg, struct df_ref **def)
{ {
abb = BLOCK_FOR_INSN (ainsn); struct df_ref *use, *adef;
basic_block def_bb, use_bb;
rtx def_insn;
bool dom_p;
*def = NULL;
if (!simple_reg_p (reg))
return GRD_INVALID;
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
gcc_assert (REG_P (reg));
if (dominated_by_p (CDI_DOMINATORS, bb, abb)) use = df_find_use (df, insn, reg);
break; gcc_assert (use != NULL);
auid = INSN_UID (ainsn); if (!DF_REF_CHAIN (use))
ainsn = insn_info[auid].prev_def; return GRD_INVARIANT;
if (!ainsn) /* More than one reaching def. */
return NULL_RTX; if (DF_REF_CHAIN (use)->next)
} return GRD_INVALID;
while (1) adef = DF_REF_CHAIN (use)->ref;
{ def_insn = DF_REF_INSN (adef);
abb = BLOCK_FOR_INSN (ainsn); def_bb = DF_REF_BB (adef);
if (abb != bb) use_bb = BLOCK_FOR_INSN (insn);
return ainsn;
auid = INSN_UID (ainsn); if (use_bb == def_bb)
if (luid > insn_info[auid].luid) dom_p = (DF_INSN_LUID (df, def_insn) < DF_INSN_LUID (df, insn));
return ainsn; else
dom_p = dominated_by_p (CDI_DOMINATORS, use_bb, def_bb);
ainsn = insn_info[auid].prev_def; if (dom_p)
if (!ainsn) {
return NULL_RTX; *def = adef;
return GRD_SINGLE_DOM;
} }
/* The definition does not dominate the use. This is still OK if
this may be a use of a biv, i.e. if the def_bb dominates loop
latch. */
if (just_once_each_iteration_p (current_loop, def_bb))
return GRD_MAYBE_BIV;
return GRD_INVALID;
} }
/* Sets IV to invariant CST in MODE. Always returns true (just for /* Sets IV to invariant CST in MODE. Always returns true (just for
...@@ -425,7 +363,6 @@ iv_constant (struct rtx_iv *iv, rtx cst, enum machine_mode mode) ...@@ -425,7 +363,6 @@ iv_constant (struct rtx_iv *iv, rtx cst, enum machine_mode mode)
if (mode == VOIDmode) if (mode == VOIDmode)
mode = GET_MODE (cst); mode = GET_MODE (cst);
iv->analysed = true;
iv->mode = mode; iv->mode = mode;
iv->base = cst; iv->base = cst;
iv->step = const0_rtx; iv->step = const0_rtx;
...@@ -653,20 +590,26 @@ iv_shift (struct rtx_iv *iv, rtx mby) ...@@ -653,20 +590,26 @@ iv_shift (struct rtx_iv *iv, rtx mby)
} }
/* The recursive part of get_biv_step. Gets the value of the single value /* The recursive part of get_biv_step. Gets the value of the single value
defined in INSN wrto initial value of REG inside loop, in shape described defined by DEF wrto initial value of REG inside loop, in shape described
at get_biv_step. */ at get_biv_step. */
static bool static bool
get_biv_step_1 (rtx insn, rtx reg, get_biv_step_1 (struct df_ref *def, rtx reg,
rtx *inner_step, enum machine_mode *inner_mode, rtx *inner_step, enum machine_mode *inner_mode,
enum rtx_code *extend, enum machine_mode outer_mode, enum rtx_code *extend, enum machine_mode outer_mode,
rtx *outer_step) rtx *outer_step)
{ {
rtx set, rhs, op0 = NULL_RTX, op1 = NULL_RTX; rtx set, rhs, op0 = NULL_RTX, op1 = NULL_RTX;
rtx next, nextr, def_insn, tmp; rtx next, nextr, tmp;
enum rtx_code code; enum rtx_code code;
rtx insn = DF_REF_INSN (def);
struct df_ref *next_def;
enum iv_grd_result res;
set = single_set (insn); set = single_set (insn);
if (!set)
return false;
rhs = find_reg_equal_equiv_note (insn); rhs = find_reg_equal_equiv_note (insn);
if (rhs) if (rhs)
rhs = XEXP (rhs, 0); rhs = XEXP (rhs, 0);
...@@ -742,11 +685,12 @@ get_biv_step_1 (rtx insn, rtx reg, ...@@ -742,11 +685,12 @@ get_biv_step_1 (rtx insn, rtx reg,
else else
nextr = next; nextr = next;
def_insn = iv_get_reaching_def (insn, nextr); res = iv_get_reaching_def (insn, nextr, &next_def);
if (def_insn == const0_rtx)
if (res == GRD_INVALID || res == GRD_INVARIANT)
return false; return false;
if (!def_insn) if (res == GRD_MAYBE_BIV)
{ {
if (!rtx_equal_p (nextr, reg)) if (!rtx_equal_p (nextr, reg))
return false; return false;
...@@ -756,7 +700,7 @@ get_biv_step_1 (rtx insn, rtx reg, ...@@ -756,7 +700,7 @@ get_biv_step_1 (rtx insn, rtx reg,
*inner_mode = outer_mode; *inner_mode = outer_mode;
*outer_step = const0_rtx; *outer_step = const0_rtx;
} }
else if (!get_biv_step_1 (def_insn, reg, else if (!get_biv_step_1 (next_def, reg,
inner_step, inner_mode, extend, outer_mode, inner_step, inner_mode, extend, outer_mode,
outer_step)) outer_step))
return false; return false;
...@@ -803,7 +747,7 @@ get_biv_step_1 (rtx insn, rtx reg, ...@@ -803,7 +747,7 @@ get_biv_step_1 (rtx insn, rtx reg,
break; break;
default: default:
gcc_unreachable (); return false;
} }
return true; return true;
...@@ -813,16 +757,17 @@ get_biv_step_1 (rtx insn, rtx reg, ...@@ -813,16 +757,17 @@ get_biv_step_1 (rtx insn, rtx reg,
OUTER_STEP + EXTEND_{OUTER_MODE} (SUBREG_{INNER_MODE} (REG + INNER_STEP)) OUTER_STEP + EXTEND_{OUTER_MODE} (SUBREG_{INNER_MODE} (REG + INNER_STEP))
If the operation cannot be described in this shape, return false. */ If the operation cannot be described in this shape, return false.
LAST_DEF is the definition of REG that dominates loop latch. */
static bool static bool
get_biv_step (rtx reg, rtx *inner_step, enum machine_mode *inner_mode, get_biv_step (struct df_ref *last_def, rtx reg, rtx *inner_step,
enum rtx_code *extend, enum machine_mode *outer_mode, enum machine_mode *inner_mode, enum rtx_code *extend,
rtx *outer_step) enum machine_mode *outer_mode, rtx *outer_step)
{ {
*outer_mode = GET_MODE (reg); *outer_mode = GET_MODE (reg);
if (!get_biv_step_1 (last_def[REGNO (reg)], reg, if (!get_biv_step_1 (last_def, reg,
inner_step, inner_mode, extend, *outer_mode, inner_step, inner_mode, extend, *outer_mode,
outer_step)) outer_step))
return false; return false;
...@@ -833,16 +778,54 @@ get_biv_step (rtx reg, rtx *inner_step, enum machine_mode *inner_mode, ...@@ -833,16 +778,54 @@ get_biv_step (rtx reg, rtx *inner_step, enum machine_mode *inner_mode,
return true; return true;
} }
/* Records information that DEF is induction variable IV. */
static void
record_iv (struct df_ref *def, struct rtx_iv *iv)
{
struct rtx_iv *recorded_iv = xmalloc (sizeof (struct rtx_iv));
*recorded_iv = *iv;
DF_REF_IV_SET (def, recorded_iv);
}
/* If DEF was already analyzed for bivness, store the description of the biv to
IV and return true. Otherwise return false. */
static bool
analyzed_for_bivness_p (rtx def, struct rtx_iv *iv)
{
struct biv_entry *biv = htab_find_with_hash (bivs, def, REGNO (def));
if (!biv)
return false;
*iv = biv->iv;
return true;
}
static void
record_biv (rtx def, struct rtx_iv *iv)
{
struct biv_entry *biv = xmalloc (sizeof (struct biv_entry));
void **slot = htab_find_slot_with_hash (bivs, def, REGNO (def), INSERT);
biv->regno = REGNO (def);
biv->iv = *iv;
gcc_assert (!*slot);
*slot = biv;
}
/* Determines whether DEF is a biv and if so, stores its description /* Determines whether DEF is a biv and if so, stores its description
to *IV. */ to *IV. */
static bool static bool
iv_analyze_biv (rtx def, struct rtx_iv *iv) iv_analyze_biv (rtx def, struct rtx_iv *iv)
{ {
unsigned regno;
rtx inner_step, outer_step; rtx inner_step, outer_step;
enum machine_mode inner_mode, outer_mode; enum machine_mode inner_mode, outer_mode;
enum rtx_code extend; enum rtx_code extend;
struct df_ref *last_def;
if (dump_file) if (dump_file)
{ {
...@@ -859,31 +842,24 @@ iv_analyze_biv (rtx def, struct rtx_iv *iv) ...@@ -859,31 +842,24 @@ iv_analyze_biv (rtx def, struct rtx_iv *iv)
return iv_constant (iv, def, VOIDmode); return iv_constant (iv, def, VOIDmode);
} }
regno = REGNO (def); if (!latch_dominating_def (def, &last_def))
if (last_def[regno] == const0_rtx)
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, " not simple.\n"); fprintf (dump_file, " not simple.\n");
return false; return false;
} }
if (last_def[regno] && bivs[regno].analysed) if (!last_def)
return iv_constant (iv, def, VOIDmode);
if (analyzed_for_bivness_p (def, iv))
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, " already analysed.\n"); fprintf (dump_file, " already analysed.\n");
*iv = bivs[regno];
return iv->base != NULL_RTX; return iv->base != NULL_RTX;
} }
if (!last_def[regno]) if (!get_biv_step (last_def, def, &inner_step, &inner_mode, &extend,
{
iv_constant (iv, def, VOIDmode);
goto end;
}
iv->analysed = true;
if (!get_biv_step (def, &inner_step, &inner_mode, &extend,
&outer_mode, &outer_step)) &outer_mode, &outer_step))
{ {
iv->base = NULL_RTX; iv->base = NULL_RTX;
...@@ -913,119 +889,154 @@ iv_analyze_biv (rtx def, struct rtx_iv *iv) ...@@ -913,119 +889,154 @@ iv_analyze_biv (rtx def, struct rtx_iv *iv)
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
} }
bivs[regno] = *iv; record_biv (def, iv);
return iv->base != NULL_RTX; return iv->base != NULL_RTX;
} }
/* Analyzes operand OP of INSN and stores the result to *IV. */ /* Analyzes expression RHS used at INSN and stores the result to *IV.
The mode of the induction variable is MODE. */
static bool bool
iv_analyze_op (rtx insn, rtx op, struct rtx_iv *iv) iv_analyze_expr (rtx insn, rtx rhs, enum machine_mode mode, struct rtx_iv *iv)
{ {
rtx def_insn; rtx mby = NULL_RTX, tmp;
unsigned regno; rtx op0 = NULL_RTX, op1 = NULL_RTX;
bool inv = CONSTANT_P (op); struct rtx_iv iv0, iv1;
enum rtx_code code = GET_CODE (rhs);
if (dump_file) enum machine_mode omode = mode;
{
fprintf (dump_file, "Analyzing operand ");
print_rtl (dump_file, op);
fprintf (dump_file, " of insn ");
print_rtl_single (dump_file, insn);
}
if (GET_CODE (op) == SUBREG)
{
if (!subreg_lowpart_p (op))
return false;
if (!iv_analyze_op (insn, SUBREG_REG (op), iv)) iv->mode = VOIDmode;
return false; iv->base = NULL_RTX;
iv->step = NULL_RTX;
return iv_subreg (iv, GET_MODE (op)); gcc_assert (GET_MODE (rhs) == mode || GET_MODE (rhs) == VOIDmode);
}
if (!inv) if (CONSTANT_P (rhs)
|| REG_P (rhs)
|| code == SUBREG)
{ {
regno = REGNO (op); if (!iv_analyze_op (insn, rhs, iv))
if (!last_def[regno]) return false;
inv = true;
else if (last_def[regno] == const0_rtx) if (iv->mode == VOIDmode)
{ {
if (dump_file) iv->mode = mode;
fprintf (dump_file, " not simple.\n"); iv->extend_mode = mode;
return false;
} }
return true;
} }
if (inv) switch (code)
{ {
iv_constant (iv, op, VOIDmode); case REG:
op0 = rhs;
break;
if (dump_file) case SIGN_EXTEND:
case ZERO_EXTEND:
case NEG:
op0 = XEXP (rhs, 0);
omode = GET_MODE (op0);
break;
case PLUS:
case MINUS:
op0 = XEXP (rhs, 0);
op1 = XEXP (rhs, 1);
break;
case MULT:
op0 = XEXP (rhs, 0);
mby = XEXP (rhs, 1);
if (!CONSTANT_P (mby))
{ {
fprintf (dump_file, " "); tmp = op0;
dump_iv_info (dump_file, iv); op0 = mby;
fprintf (dump_file, "\n"); mby = tmp;
} }
return true; if (!CONSTANT_P (mby))
} return false;
break;
def_insn = iv_get_reaching_def (insn, op); case ASHIFT:
if (def_insn == const0_rtx) op0 = XEXP (rhs, 0);
{ mby = XEXP (rhs, 1);
if (dump_file) if (!CONSTANT_P (mby))
fprintf (dump_file, " not simple.\n"); return false;
break;
default:
return false; return false;
} }
return iv_analyze (def_insn, op, iv); if (op0
} && !iv_analyze_expr (insn, op0, omode, &iv0))
return false;
/* Analyzes iv DEF defined in INSN and stores the result to *IV. */
bool
iv_analyze (rtx insn, rtx def, struct rtx_iv *iv)
{
unsigned uid;
rtx set, rhs, mby = NULL_RTX, tmp;
rtx op0 = NULL_RTX, op1 = NULL_RTX;
struct rtx_iv iv0, iv1;
enum machine_mode amode;
enum rtx_code code;
if (insn == const0_rtx) if (op1
&& !iv_analyze_expr (insn, op1, omode, &iv1))
return false; return false;
if (GET_CODE (def) == SUBREG) switch (code)
{ {
if (!subreg_lowpart_p (def)) case SIGN_EXTEND:
case ZERO_EXTEND:
if (!iv_extend (&iv0, code, mode))
return false;
break;
case NEG:
if (!iv_neg (&iv0))
return false; return false;
break;
if (!iv_analyze (insn, SUBREG_REG (def), iv)) case PLUS:
case MINUS:
if (!iv_add (&iv0, &iv1, code))
return false; return false;
break;
return iv_subreg (iv, GET_MODE (def)); case MULT:
if (!iv_mult (&iv0, mby))
return false;
break;
case ASHIFT:
if (!iv_shift (&iv0, mby))
return false;
break;
default:
break;
} }
if (!insn) *iv = iv0;
return iv_analyze_biv (def, iv); return iv->base != NULL_RTX;
}
/* Analyzes iv DEF and stores the result to *IV. */
static bool
iv_analyze_def (struct df_ref *def, struct rtx_iv *iv)
{
rtx insn = DF_REF_INSN (def);
rtx reg = DF_REF_REG (def);
rtx set, rhs;
if (dump_file) if (dump_file)
{ {
fprintf (dump_file, "Analyzing def of "); fprintf (dump_file, "Analysing def of ");
print_rtl (dump_file, def); print_rtl (dump_file, reg);
fprintf (dump_file, " in insn "); fprintf (dump_file, " in insn ");
print_rtl_single (dump_file, insn); print_rtl_single (dump_file, insn);
} }
uid = INSN_UID (insn); if (DF_REF_IV (def))
if (insn_info[uid].iv.analysed)
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, " already analysed.\n"); fprintf (dump_file, " already analysed.\n");
*iv = insn_info[uid].iv; *iv = *DF_REF_IV (def);
return iv->base != NULL_RTX; return iv->base != NULL_RTX;
} }
...@@ -1034,146 +1045,129 @@ iv_analyze (rtx insn, rtx def, struct rtx_iv *iv) ...@@ -1034,146 +1045,129 @@ iv_analyze (rtx insn, rtx def, struct rtx_iv *iv)
iv->step = NULL_RTX; iv->step = NULL_RTX;
set = single_set (insn); set = single_set (insn);
if (!set || SET_DEST (set) != reg)
return false;
rhs = find_reg_equal_equiv_note (insn); rhs = find_reg_equal_equiv_note (insn);
if (rhs) if (rhs)
rhs = XEXP (rhs, 0); rhs = XEXP (rhs, 0);
else else
rhs = SET_SRC (set); rhs = SET_SRC (set);
code = GET_CODE (rhs);
if (CONSTANT_P (rhs)) iv_analyze_expr (insn, rhs, GET_MODE (reg), iv);
record_iv (def, iv);
if (dump_file)
{ {
op0 = rhs; print_rtl (dump_file, reg);
amode = GET_MODE (def); fprintf (dump_file, " in insn ");
print_rtl_single (dump_file, insn);
fprintf (dump_file, " is ");
dump_iv_info (dump_file, iv);
fprintf (dump_file, "\n");
} }
else
{
switch (code)
{
case SUBREG:
if (!subreg_lowpart_p (rhs))
goto end;
op0 = rhs;
break;
case REG:
op0 = rhs;
break;
case SIGN_EXTEND: return iv->base != NULL_RTX;
case ZERO_EXTEND: }
case NEG:
op0 = XEXP (rhs, 0);
break;
case PLUS: /* Analyzes operand OP of INSN and stores the result to *IV. */
case MINUS:
op0 = XEXP (rhs, 0);
op1 = XEXP (rhs, 1);
break;
case MULT: static bool
op0 = XEXP (rhs, 0); iv_analyze_op (rtx insn, rtx op, struct rtx_iv *iv)
mby = XEXP (rhs, 1); {
if (!CONSTANT_P (mby)) struct df_ref *def = NULL;
{ enum iv_grd_result res;
gcc_assert (CONSTANT_P (op0));
tmp = op0;
op0 = mby;
mby = tmp;
}
break;
case ASHIFT: if (dump_file)
gcc_assert (!CONSTANT_P (XEXP (rhs, 0))); {
op0 = XEXP (rhs, 0); fprintf (dump_file, "Analysing operand ");
mby = XEXP (rhs, 1); print_rtl (dump_file, op);
break; fprintf (dump_file, " of insn ");
print_rtl_single (dump_file, insn);
}
default: if (CONSTANT_P (op))
gcc_unreachable (); res = GRD_INVARIANT;
} else if (GET_CODE (op) == SUBREG)
{
if (!subreg_lowpart_p (op))
return false;
amode = GET_MODE (rhs); if (!iv_analyze_op (insn, SUBREG_REG (op), iv))
} return false;
if (op0) return iv_subreg (iv, GET_MODE (op));
}
else
{ {
if (!iv_analyze_op (insn, op0, &iv0)) res = iv_get_reaching_def (insn, op, &def);
goto end; if (res == GRD_INVALID)
if (iv0.mode == VOIDmode)
{ {
iv0.mode = amode; if (dump_file)
iv0.extend_mode = amode; fprintf (dump_file, " not simple.\n");
return false;
} }
} }
if (op1) if (res == GRD_INVARIANT)
{ {
if (!iv_analyze_op (insn, op1, &iv1)) iv_constant (iv, op, VOIDmode);
goto end;
if (iv1.mode == VOIDmode) if (dump_file)
{ {
iv1.mode = amode; fprintf (dump_file, " ");
iv1.extend_mode = amode; dump_iv_info (dump_file, iv);
fprintf (dump_file, "\n");
} }
return true;
} }
switch (code) if (res == GRD_MAYBE_BIV)
{ return iv_analyze_biv (op, iv);
case SIGN_EXTEND:
case ZERO_EXTEND:
if (!iv_extend (&iv0, code, amode))
goto end;
break;
case NEG: return iv_analyze_def (def, iv);
if (!iv_neg (&iv0)) }
goto end;
break;
case PLUS: /* Analyzes value VAL at INSN and stores the result to *IV. */
case MINUS:
if (!iv_add (&iv0, &iv1, code))
goto end;
break;
case MULT: bool
if (!iv_mult (&iv0, mby)) iv_analyze (rtx insn, rtx val, struct rtx_iv *iv)
goto end; {
break; rtx reg;
case ASHIFT: /* We must find the insn in that val is used, so that we get to UD chains.
if (!iv_shift (&iv0, mby)) Since the function is sometimes called on result of get_condition,
goto end; this does not necessarily have to be directly INSN; scan also the
break; following insns. */
if (simple_reg_p (val))
{
if (GET_CODE (val) == SUBREG)
reg = SUBREG_REG (val);
else
reg = val;
default: while (!df_find_use (df, insn, reg))
break; insn = NEXT_INSN (insn);
} }
*iv = iv0; return iv_analyze_op (insn, val, iv);
}
end: /* Analyzes definition of DEF in INSN and stores the result to IV. */
iv->analysed = true;
insn_info[uid].iv = *iv;
if (dump_file) bool
{ iv_analyze_result (rtx insn, rtx def, struct rtx_iv *iv)
print_rtl (dump_file, def); {
fprintf (dump_file, " in insn "); struct df_ref *adef;
print_rtl_single (dump_file, insn);
fprintf (dump_file, " is ");
dump_iv_info (dump_file, iv);
fprintf (dump_file, "\n");
}
return iv->base != NULL_RTX; adef = df_find_def (df, insn, def);
if (!adef)
return false;
return iv_analyze_def (adef, iv);
} }
/* Checks whether definition of register REG in INSN a basic induction /* Checks whether definition of register REG in INSN is a basic induction
variable. IV analysis must have been initialized (via a call to variable. IV analysis must have been initialized (via a call to
iv_analysis_loop_init) for this function to produce a result. */ iv_analysis_loop_init) for this function to produce a result. */
...@@ -1181,14 +1175,22 @@ bool ...@@ -1181,14 +1175,22 @@ bool
biv_p (rtx insn, rtx reg) biv_p (rtx insn, rtx reg)
{ {
struct rtx_iv iv; struct rtx_iv iv;
struct df_ref *def, *last_def;
if (!REG_P (reg)) if (!simple_reg_p (reg))
return false; return false;
if (last_def[REGNO (reg)] != insn) def = df_find_def (df, insn, reg);
gcc_assert (def != NULL);
if (!latch_dominating_def (reg, &last_def))
return false;
if (last_def != def)
return false; return false;
return iv_analyze_biv (reg, &iv); if (!iv_analyze_biv (reg, &iv))
return false;
return iv.step != const0_rtx;
} }
/* Calculates value of IV at ITERATION-th iteration. */ /* Calculates value of IV at ITERATION-th iteration. */
...@@ -1230,21 +1232,12 @@ get_iv_value (struct rtx_iv *iv, rtx iteration) ...@@ -1230,21 +1232,12 @@ get_iv_value (struct rtx_iv *iv, rtx iteration)
void void
iv_analysis_done (void) iv_analysis_done (void)
{ {
max_insn_no = 0; if (df)
max_reg_no = 0;
if (insn_info)
{
free (insn_info);
insn_info = NULL;
}
if (last_def)
{
free (last_def);
last_def = NULL;
}
if (bivs)
{ {
free (bivs); clear_iv_info ();
df_finish (df);
df = NULL;
htab_delete (bivs);
bivs = NULL; bivs = NULL;
} }
} }
...@@ -1996,7 +1989,7 @@ static void ...@@ -1996,7 +1989,7 @@ static void
iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition, iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition,
struct niter_desc *desc) struct niter_desc *desc)
{ {
rtx op0, op1, delta, step, bound, may_xform, def_insn, tmp, tmp0, tmp1; rtx op0, op1, delta, step, bound, may_xform, tmp, tmp0, tmp1;
struct rtx_iv iv0, iv1, tmp_iv; struct rtx_iv iv0, iv1, tmp_iv;
rtx assumption, may_not_xform; rtx assumption, may_not_xform;
enum rtx_code cond; enum rtx_code cond;
...@@ -2038,15 +2031,13 @@ iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition, ...@@ -2038,15 +2031,13 @@ iv_number_of_iterations (struct loop *loop, rtx insn, rtx condition,
goto fail; goto fail;
op0 = XEXP (condition, 0); op0 = XEXP (condition, 0);
def_insn = iv_get_reaching_def (insn, op0); if (!iv_analyze (insn, op0, &iv0))
if (!iv_analyze (def_insn, op0, &iv0))
goto fail; goto fail;
if (iv0.extend_mode == VOIDmode) if (iv0.extend_mode == VOIDmode)
iv0.mode = iv0.extend_mode = mode; iv0.mode = iv0.extend_mode = mode;
op1 = XEXP (condition, 1); op1 = XEXP (condition, 1);
def_insn = iv_get_reaching_def (insn, op1); if (!iv_analyze (insn, op1, &iv1))
if (!iv_analyze (def_insn, op1, &iv1))
goto fail; goto fail;
if (iv1.extend_mode == VOIDmode) if (iv1.extend_mode == VOIDmode)
iv1.mode = iv1.extend_mode = mode; iv1.mode = iv1.extend_mode = mode;
......
...@@ -33,7 +33,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ...@@ -33,7 +33,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "expr.h" #include "expr.h"
#include "hashtab.h" #include "hashtab.h"
#include "recog.h" #include "recog.h"
#include "varray.h"
/* This pass performs loop unrolling and peeling. We only perform these /* This pass performs loop unrolling and peeling. We only perform these
optimizations on innermost loops (with single exception) because optimizations on innermost loops (with single exception) because
...@@ -1670,7 +1669,7 @@ analyze_iv_to_split_insn (rtx insn) ...@@ -1670,7 +1669,7 @@ analyze_iv_to_split_insn (rtx insn)
if (!biv_p (insn, dest)) if (!biv_p (insn, dest))
return NULL; return NULL;
ok = iv_analyze (insn, dest, &iv); ok = iv_analyze_result (insn, dest, &iv);
gcc_assert (ok); gcc_assert (ok);
if (iv.step == const0_rtx if (iv.step == const0_rtx
......
...@@ -172,7 +172,7 @@ unswitch_loops (struct loops *loops) ...@@ -172,7 +172,7 @@ unswitch_loops (struct loops *loops)
static rtx static rtx
may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn) may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn)
{ {
rtx test, at, insn, op[2], stest; rtx test, at, op[2], stest;
struct rtx_iv iv; struct rtx_iv iv;
unsigned i; unsigned i;
enum machine_mode mode; enum machine_mode mode;
...@@ -205,8 +205,7 @@ may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn) ...@@ -205,8 +205,7 @@ may_unswitch_on (basic_block bb, struct loop *loop, rtx *cinsn)
if (CONSTANT_P (op[i])) if (CONSTANT_P (op[i]))
continue; continue;
insn = iv_get_reaching_def (at, op[i]); if (!iv_analyze (at, op[i], &iv))
if (!iv_analyze (insn, op[i], &iv))
return NULL_RTX; return NULL_RTX;
if (iv.step != const0_rtx if (iv.step != const0_rtx
|| iv.first_special) || iv.first_special)
......
...@@ -2721,7 +2721,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target, ...@@ -2721,7 +2721,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
target = gen_reg_rtx (outmode); target = gen_reg_rtx (outmode);
emit_libcall_block (insns, target, value, emit_libcall_block (insns, target, value,
gen_rtx_fmt_e (unoptab->code, mode, op0)); gen_rtx_fmt_e (unoptab->code, outmode, op0));
return target; return target;
} }
......
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