You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "expr.h"
#include "hashtab.h"
#include "recog.h"
-#include "varray.h"
/* This pass performs loop unrolling and peeling. We only perform these
optimizations on innermost loops (with single exception) because
{
rtx insn; /* The insn in that the variable expansion occurs. */
rtx reg; /* The accumulator which is expanded. */
- varray_type var_expansions; /* The copies of the accumulator which is expanded. */
+ VEC(rtx,heap) *var_expansions; /* The copies of the accumulator which is expanded. */
enum rtx_code op; /* The type of the accumulation - addition, subtraction
or multiplication. */
int expansion_count; /* Count the number of expansions generated so far. */
/* Check number of iterations. */
if (!desc->simple_p
|| desc->assumptions
+ || desc->infinite
|| !desc->const_iter
|| desc->niter != 0)
{
/* Check number of iterations. */
if (!desc->simple_p
|| desc->assumptions
- || !desc->const_iter)
+ || !desc->const_iter
+ || desc->infinite)
{
if (dump_file)
fprintf (dump_file,
if (npeel)
{
+ bool ok;
+
wont_exit = sbitmap_alloc (npeel + 1);
sbitmap_ones (wont_exit);
RESET_BIT (wont_exit, 0);
if (desc->noloop_assumptions)
RESET_BIT (wont_exit, 1);
- remove_edges = xcalloc (npeel, sizeof (edge));
+ remove_edges = XCNEWVEC (edge, npeel);
n_remove_edges = 0;
if (flag_split_ivs_in_unroller)
opt_info = analyze_insns_in_loop (loop);
opt_info_start_duplication (opt_info);
- if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
- loops, npeel,
- wont_exit, desc->out_edge, remove_edges, &n_remove_edges,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ ok = duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
+ loops, npeel,
+ wont_exit, desc->out_edge,
+ remove_edges, &n_remove_edges,
+ DLTHE_FLAG_UPDATE_FREQ
+ | DLTHE_FLAG_COMPLETTE_PEEL
+ | (opt_info
+ ? DLTHE_RECORD_COPY_NUMBER : 0));
+ gcc_assert (ok);
free (wont_exit);
struct niter_desc *desc = get_simple_loop_desc (loop);
bool exit_at_end = loop_exit_at_end_p (loop);
struct opt_info *opt_info = NULL;
+ bool ok;
niter = desc->niter;
wont_exit = sbitmap_alloc (max_unroll + 1);
sbitmap_ones (wont_exit);
- remove_edges = xcalloc (max_unroll + exit_mod + 1, sizeof (edge));
+ remove_edges = XCNEWVEC (edge, max_unroll + exit_mod + 1);
n_remove_edges = 0;
if (flag_split_ivs_in_unroller
|| flag_variable_expansion_in_unroller)
if (exit_mod)
{
opt_info_start_duplication (opt_info);
- if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
+ ok = duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
loops, exit_mod,
wont_exit, desc->out_edge,
remove_edges, &n_remove_edges,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ DLTHE_FLAG_UPDATE_FREQ
+ | (opt_info && exit_mod > 1
+ ? DLTHE_RECORD_COPY_NUMBER
+ : 0));
+ gcc_assert (ok);
if (opt_info && exit_mod > 1)
apply_opt_in_copies (opt_info, exit_mod, false, false);
RESET_BIT (wont_exit, 1);
opt_info_start_duplication (opt_info);
- if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
- loops, exit_mod + 1,
- wont_exit, desc->out_edge, remove_edges, &n_remove_edges,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ ok = duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
+ loops, exit_mod + 1,
+ wont_exit, desc->out_edge,
+ remove_edges, &n_remove_edges,
+ DLTHE_FLAG_UPDATE_FREQ
+ | (opt_info && exit_mod > 0
+ ? DLTHE_RECORD_COPY_NUMBER
+ : 0));
+ gcc_assert (ok);
if (opt_info && exit_mod > 0)
apply_opt_in_copies (opt_info, exit_mod + 1, false, false);
/* Now unroll the loop. */
opt_info_start_duplication (opt_info);
- if (!duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
- loops, max_unroll,
- wont_exit, desc->out_edge, remove_edges, &n_remove_edges,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ ok = duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
+ loops, max_unroll,
+ wont_exit, desc->out_edge,
+ remove_edges, &n_remove_edges,
+ DLTHE_FLAG_UPDATE_FREQ
+ | (opt_info
+ ? DLTHE_RECORD_COPY_NUMBER
+ : 0));
+ gcc_assert (ok);
if (opt_info)
{
if (exit_at_end)
{
- basic_block exit_block = desc->in_edge->src->rbi->copy;
+ basic_block exit_block = get_bb_copy (desc->in_edge->src);
/* Find a new in and out edge; they are in the last copy we have made. */
if (EDGE_SUCC (exit_block, 0)->dest == desc->out_edge->dest)
struct niter_desc *desc = get_simple_loop_desc (loop);
bool exit_at_end = loop_exit_at_end_p (loop);
struct opt_info *opt_info = NULL;
+ bool ok;
if (flag_split_ivs_in_unroller
|| flag_variable_expansion_in_unroller)
opt_info = analyze_insns_in_loop (loop);
/* Remember blocks whose dominators will have to be updated. */
- dom_bbs = xcalloc (n_basic_blocks, sizeof (basic_block));
+ dom_bbs = XCNEWVEC (basic_block, n_basic_blocks);
n_dom_bbs = 0;
body = get_loop_body (loop);
/* Precondition the loop. */
loop_split_edge_with (loop_preheader_edge (loop), init_code);
- remove_edges = xcalloc (max_unroll + n_peel + 1, sizeof (edge));
+ remove_edges = XCNEWVEC (edge, max_unroll + n_peel + 1);
n_remove_edges = 0;
wont_exit = sbitmap_alloc (max_unroll + 2);
&& !desc->noloop_assumptions)
SET_BIT (wont_exit, 1);
ezc_swtch = loop_preheader_edge (loop)->src;
- if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
- loops, 1,
- wont_exit, desc->out_edge, remove_edges, &n_remove_edges,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ ok = duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
+ loops, 1,
+ wont_exit, desc->out_edge,
+ remove_edges, &n_remove_edges,
+ DLTHE_FLAG_UPDATE_FREQ);
+ gcc_assert (ok);
/* Record the place where switch will be built for preconditioning. */
swtch = loop_split_edge_with (loop_preheader_edge (loop),
sbitmap_zero (wont_exit);
if (i != n_peel - 1 || !last_may_exit)
SET_BIT (wont_exit, 1);
- if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
- loops, 1,
- wont_exit, desc->out_edge, remove_edges, &n_remove_edges,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ ok = duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
+ loops, 1,
+ wont_exit, desc->out_edge,
+ remove_edges, &n_remove_edges,
+ DLTHE_FLAG_UPDATE_FREQ);
+ gcc_assert (ok);
/* Create item for switch. */
j = n_peel - i - (extra_zero_check ? 0 : 1);
preheader = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
branch_code = compare_and_jump_seq (copy_rtx (niter), GEN_INT (j), EQ,
- block_label (preheader), p, NULL_RTX);
+ block_label (preheader), p,
+ NULL_RTX);
- swtch = loop_split_edge_with (EDGE_PRED (swtch, 0), branch_code);
+ swtch = loop_split_edge_with (single_pred_edge (swtch), branch_code);
set_immediate_dominator (CDI_DOMINATORS, preheader, swtch);
- EDGE_SUCC (swtch, 0)->probability = REG_BR_PROB_BASE - p;
+ single_pred_edge (swtch)->probability = REG_BR_PROB_BASE - p;
e = make_edge (swtch, preheader,
- EDGE_SUCC (swtch, 0)->flags & EDGE_IRREDUCIBLE_LOOP);
+ single_succ_edge (swtch)->flags & EDGE_IRREDUCIBLE_LOOP);
e->probability = p;
}
swtch = ezc_swtch;
preheader = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
branch_code = compare_and_jump_seq (copy_rtx (niter), const0_rtx, EQ,
- block_label (preheader), p, NULL_RTX);
+ block_label (preheader), p,
+ NULL_RTX);
- swtch = loop_split_edge_with (EDGE_SUCC (swtch, 0), branch_code);
+ swtch = loop_split_edge_with (single_succ_edge (swtch), branch_code);
set_immediate_dominator (CDI_DOMINATORS, preheader, swtch);
- EDGE_SUCC (swtch, 0)->probability = REG_BR_PROB_BASE - p;
+ single_succ_edge (swtch)->probability = REG_BR_PROB_BASE - p;
e = make_edge (swtch, preheader,
- EDGE_SUCC (swtch, 0)->flags & EDGE_IRREDUCIBLE_LOOP);
+ single_succ_edge (swtch)->flags & EDGE_IRREDUCIBLE_LOOP);
e->probability = p;
}
RESET_BIT (wont_exit, may_exit_copy);
opt_info_start_duplication (opt_info);
- if (!duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
- loops, max_unroll,
- wont_exit, desc->out_edge, remove_edges, &n_remove_edges,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ ok = duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
+ loops, max_unroll,
+ wont_exit, desc->out_edge,
+ remove_edges, &n_remove_edges,
+ DLTHE_FLAG_UPDATE_FREQ
+ | (opt_info
+ ? DLTHE_RECORD_COPY_NUMBER
+ : 0));
+ gcc_assert (ok);
if (opt_info)
{
if (exit_at_end)
{
- basic_block exit_block = desc->in_edge->src->rbi->copy;
- /* Find a new in and out edge; they are in the last copy we have made. */
+ basic_block exit_block = get_bb_copy (desc->in_edge->src);
+ /* Find a new in and out edge; they are in the last copy we have
+ made. */
if (EDGE_SUCC (exit_block, 0)->dest == desc->out_edge->dest)
{
the correct new number of iterations is this: */
gcc_assert (!desc->const_iter);
desc->niter_expr =
- simplify_gen_binary (UDIV, desc->mode, old_niter, GEN_INT (max_unroll + 1));
+ simplify_gen_binary (UDIV, desc->mode, old_niter,
+ GEN_INT (max_unroll + 1));
desc->niter_max /= max_unroll + 1;
if (exit_at_end)
{
";; Unrolled loop %d times, counting # of iterations "
"in runtime, %i insns\n",
max_unroll, num_loop_insns (loop));
+
+ if (dom_bbs)
+ free (dom_bbs);
}
/* Decide whether to simply peel LOOP and how much. */
unsigned npeel = loop->lpt_decision.times;
struct niter_desc *desc = get_simple_loop_desc (loop);
struct opt_info *opt_info = NULL;
+ bool ok;
if (flag_split_ivs_in_unroller && npeel > 1)
opt_info = analyze_insns_in_loop (loop);
opt_info_start_duplication (opt_info);
- if (!duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
- loops, npeel, wont_exit, NULL, NULL, NULL,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ ok = duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
+ loops, npeel, wont_exit,
+ NULL, NULL,
+ NULL, DLTHE_FLAG_UPDATE_FREQ
+ | (opt_info
+ ? DLTHE_RECORD_COPY_NUMBER
+ : 0));
+ gcc_assert (ok);
free (wont_exit);
unsigned nunroll = loop->lpt_decision.times;
struct niter_desc *desc = get_simple_loop_desc (loop);
struct opt_info *opt_info = NULL;
+ bool ok;
if (flag_split_ivs_in_unroller
|| flag_variable_expansion_in_unroller)
sbitmap_zero (wont_exit);
opt_info_start_duplication (opt_info);
- if (!duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
- loops, nunroll, wont_exit, NULL, NULL, NULL,
- DLTHE_FLAG_UPDATE_FREQ))
- abort ();
+ ok = duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
+ loops, nunroll, wont_exit,
+ NULL, NULL, NULL,
+ DLTHE_FLAG_UPDATE_FREQ
+ | (opt_info
+ ? DLTHE_RECORD_COPY_NUMBER
+ : 0));
+ gcc_assert (ok);
if (opt_info)
{
&& GET_CODE (src) != MINUS
&& GET_CODE (src) != MULT)
return NULL;
-
+
+ /* Hmm, this is a bit paradoxical. We know that INSN is a valid insn
+ in MD. But if there is no optab to generate the insn, we can not
+ perform the variable expansion. This can happen if an MD provides
+ an insn but not a named pattern to generate it, for example to avoid
+ producing code that needs additional mode switches like for x87/mmx.
+
+ So we check have_insn_for which looks for an optab for the operation
+ in SRC. If it doesn't exist, we can't perform the expansion even
+ though INSN is valid. */
+ if (!have_insn_for (GET_CODE (src), GET_MODE (src)))
+ return NULL;
+
if (!XEXP (src, 0))
return NULL;
return NULL;
/* Record the accumulator to expand. */
- ves = xmalloc (sizeof (struct var_to_expand));
+ ves = XNEW (struct var_to_expand);
ves->insn = insn;
- VARRAY_RTX_INIT (ves->var_expansions, 1, "var_expansions");
+ ves->var_expansions = VEC_alloc (rtx, heap, 1);
ves->reg = copy_rtx (dest);
ves->op = GET_CODE (src);
ves->expansion_count = 0;
rtx set, dest;
struct rtx_iv iv;
struct iv_to_split *ivts;
+ bool ok;
/* For now we just split the basic induction variables. Later this may be
extended for example by selecting also addresses of memory references. */
if (!biv_p (insn, dest))
return NULL;
- if (!iv_analyze (insn, dest, &iv))
- abort ();
+ ok = iv_analyze_result (insn, dest, &iv);
+
+ /* This used to be an assert under the assumption that if biv_p returns
+ true that iv_analyze_result must also return true. However, that
+ assumption is not strictly correct as evidenced by pr25569.
+
+ Returning NULL when iv_analyze_result returns false is safe and
+ avoids the problems in pr25569 until the iv_analyze_* routines
+ can be fixed, which is apparently hard and time consuming
+ according to their author. */
+ if (! ok)
+ return NULL;
if (iv.step == const0_rtx
|| iv.mode != iv.extend_mode)
return NULL;
/* Record the insn to split. */
- ivts = xmalloc (sizeof (struct iv_to_split));
+ ivts = XNEW (struct iv_to_split);
ivts->insn = insn;
ivts->base_var = NULL_RTX;
ivts->step = iv.step;
analyze_insns_in_loop (struct loop *loop)
{
basic_block *body, bb;
- unsigned i, n_edges = 0;
- struct opt_info *opt_info = xcalloc (1, sizeof (struct opt_info));
+ unsigned i, num_edges = 0;
+ struct opt_info *opt_info = XCNEW (struct opt_info);
rtx insn;
struct iv_to_split *ivts = NULL;
struct var_to_expand *ves = NULL;
PTR *slot1;
PTR *slot2;
- edge *edges = get_loop_exit_edges (loop, &n_edges);
- basic_block preheader;
+ edge *edges = get_loop_exit_edges (loop, &num_edges);
bool can_apply = false;
iv_analysis_loop_init (loop);
/* Record the loop exit bb and loop preheader before the unrolling. */
if (!loop_preheader_edge (loop)->src)
{
- preheader = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
+ loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
opt_info->loop_preheader = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
}
else
opt_info->loop_preheader = loop_preheader_edge (loop)->src;
- if (n_edges == 1
+ if (num_edges == 1
&& !(edges[0]->flags & EDGE_COMPLEX))
{
opt_info->loop_exit = loop_split_edge_with (edges[0], NULL_RTX);
if (ve->reuse_expansion == 0)
reg = ve->reg;
else
- reg = VARRAY_RTX (ve->var_expansions, ve->reuse_expansion - 1);
+ reg = VEC_index (rtx, ve->var_expansions, ve->reuse_expansion - 1);
- if (VARRAY_ACTIVE_SIZE (ve->var_expansions) == (unsigned) ve->reuse_expansion)
+ if (VEC_length (rtx, ve->var_expansions) == (unsigned) ve->reuse_expansion)
ve->reuse_expansion = 0;
else
ve->reuse_expansion++;
bool really_new_expansion = false;
set = single_set (insn);
- if (!set)
- abort ();
+ gcc_assert (set);
/* Generate a new register only if the expansion limit has not been
reached. Else reuse an already existing expansion. */
if (apply_change_group ())
if (really_new_expansion)
{
- VARRAY_PUSH_RTX (ve->var_expansions, new_reg);
+ VEC_safe_push (rtx, heap, ve->var_expansions, new_reg);
ve->expansion_count++;
}
}
rtx seq, var, zero_init, insn;
unsigned i;
- if (VARRAY_ACTIVE_SIZE (ve->var_expansions) == 0)
+ if (VEC_length (rtx, ve->var_expansions) == 0)
return 1;
start_sequence ();
if (ve->op == PLUS || ve->op == MINUS)
- for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+ for (i = 0; VEC_iterate (rtx, ve->var_expansions, i, var); i++)
{
- var = VARRAY_RTX (ve->var_expansions, i);
zero_init = CONST0_RTX (GET_MODE (var));
emit_move_insn (var, zero_init);
}
else if (ve->op == MULT)
- for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+ for (i = 0; VEC_iterate (rtx, ve->var_expansions, i, var); i++)
{
- var = VARRAY_RTX (ve->var_expansions, i);
zero_init = CONST1_RTX (GET_MODE (var));
emit_move_insn (var, zero_init);
}
rtx expr, seq, var, insn;
unsigned i;
- if (VARRAY_ACTIVE_SIZE (ve->var_expansions) == 0)
+ if (VEC_length (rtx, ve->var_expansions) == 0)
return 1;
start_sequence ();
if (ve->op == PLUS || ve->op == MINUS)
- for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+ for (i = 0; VEC_iterate (rtx, ve->var_expansions, i, var); i++)
{
- var = VARRAY_RTX (ve->var_expansions, i);
sum = simplify_gen_binary (PLUS, GET_MODE (ve->reg),
var, sum);
}
else if (ve->op == MULT)
- for (i = 0; i < VARRAY_ACTIVE_SIZE (ve->var_expansions); i++)
+ for (i = 0; VEC_iterate (rtx, ve->var_expansions, i, var); i++)
{
- var = VARRAY_RTX (ve->var_expansions, i);
sum = simplify_gen_binary (MULT, GET_MODE (ve->reg),
var, sum);
}
for (i = opt_info->first_new_block; i < (unsigned) last_basic_block; i++)
{
bb = BASIC_BLOCK (i);
- orig_bb = bb->rbi->original;
+ orig_bb = get_bb_original (bb);
- delta = determine_split_iv_delta (bb->rbi->copy_number, n_copies,
+ /* bb->aux holds position in copy sequence initialized by
+ duplicate_loop_to_header_edge. */
+ delta = determine_split_iv_delta ((size_t)bb->aux, n_copies,
unrolling);
+ bb->aux = 0;
orig_insn = BB_HEAD (orig_bb);
for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); insn = next)
{
if (ivts)
{
-#ifdef ENABLE_CHECKING
- gcc_assert (rtx_equal_p (PATTERN (insn), PATTERN (orig_insn)));
-#endif
+ gcc_assert (GET_CODE (PATTERN (insn))
+ == GET_CODE (PATTERN (orig_insn)));
if (!delta)
insert_base_initialization (ivts, insn);
ves = htab_find (opt_info->insns_with_var_to_expand, &ve_templ);
if (ves)
{
-#ifdef ENABLE_CHECKING
- gcc_assert (rtx_equal_p (PATTERN (insn), PATTERN (orig_insn)));
-#endif
+ gcc_assert (GET_CODE (PATTERN (insn))
+ == GET_CODE (PATTERN (orig_insn)));
expand_var_during_unrolling (ves, insn);
}
}
/* Rewrite also the original loop body. Find them as originals of the blocks
in the last copied iteration, i.e. those that have
- bb->rbi->original->copy == bb. */
+ get_bb_copy (get_bb_original (bb)) == bb. */
for (i = opt_info->first_new_block; i < (unsigned) last_basic_block; i++)
{
bb = BASIC_BLOCK (i);
- orig_bb = bb->rbi->original;
- if (orig_bb->rbi->copy != bb)
+ orig_bb = get_bb_original (bb);
+ if (get_bb_copy (orig_bb) != bb)
continue;
delta = determine_split_iv_delta (0, n_copies, unrolling);
{
struct var_to_expand *ve = *slot;
- VARRAY_CLEAR (ve->var_expansions);
+ VEC_free (rtx, heap, ve->var_expansions);
/* Continue traversing the hash table. */
return 1;