138fd1498Szrj /* Loop header copying on trees.
238fd1498Szrj Copyright (C) 2004-2018 Free Software Foundation, Inc.
338fd1498Szrj
438fd1498Szrj This file is part of GCC.
538fd1498Szrj
638fd1498Szrj GCC is free software; you can redistribute it and/or modify it
738fd1498Szrj under the terms of the GNU General Public License as published by the
838fd1498Szrj Free Software Foundation; either version 3, or (at your option) any
938fd1498Szrj later version.
1038fd1498Szrj
1138fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT
1238fd1498Szrj ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1338fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1438fd1498Szrj for more details.
1538fd1498Szrj
1638fd1498Szrj You should have received a copy of the GNU General Public License
1738fd1498Szrj along with GCC; see the file COPYING3. If not see
1838fd1498Szrj <http://www.gnu.org/licenses/>. */
1938fd1498Szrj
2038fd1498Szrj #include "config.h"
2138fd1498Szrj #include "system.h"
2238fd1498Szrj #include "coretypes.h"
2338fd1498Szrj #include "backend.h"
2438fd1498Szrj #include "tree.h"
2538fd1498Szrj #include "gimple.h"
2638fd1498Szrj #include "cfghooks.h"
2738fd1498Szrj #include "tree-pass.h"
2838fd1498Szrj #include "gimple-ssa.h"
2938fd1498Szrj #include "gimple-iterator.h"
3038fd1498Szrj #include "tree-cfg.h"
3138fd1498Szrj #include "tree-into-ssa.h"
3238fd1498Szrj #include "cfgloop.h"
3338fd1498Szrj #include "tree-inline.h"
3438fd1498Szrj #include "tree-ssa-scopedtables.h"
3538fd1498Szrj #include "tree-ssa-threadedge.h"
3638fd1498Szrj #include "params.h"
3738fd1498Szrj
3838fd1498Szrj /* Duplicates headers of loops if they are small enough, so that the statements
3938fd1498Szrj in the loop body are always executed when the loop is entered. This
4038fd1498Szrj increases effectiveness of code motion optimizations, and reduces the need
4138fd1498Szrj for loop preconditioning. */
4238fd1498Szrj
4338fd1498Szrj /* Check whether we should duplicate HEADER of LOOP. At most *LIMIT
4438fd1498Szrj instructions should be duplicated, limit is decreased by the actual
4538fd1498Szrj amount. */
4638fd1498Szrj
4738fd1498Szrj static bool
should_duplicate_loop_header_p(basic_block header,struct loop * loop,int * limit)4838fd1498Szrj should_duplicate_loop_header_p (basic_block header, struct loop *loop,
4938fd1498Szrj int *limit)
5038fd1498Szrj {
5138fd1498Szrj gimple_stmt_iterator bsi;
5238fd1498Szrj gimple *last;
5338fd1498Szrj
5438fd1498Szrj gcc_assert (!header->aux);
5538fd1498Szrj
5638fd1498Szrj /* Loop header copying usually increases size of the code. This used not to
5738fd1498Szrj be true, since quite often it is possible to verify that the condition is
5838fd1498Szrj satisfied in the first iteration and therefore to eliminate it. Jump
5938fd1498Szrj threading handles these cases now. */
6038fd1498Szrj if (optimize_loop_for_size_p (loop)
6138fd1498Szrj && !loop->force_vectorize)
6238fd1498Szrj {
6338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
6438fd1498Szrj fprintf (dump_file,
6538fd1498Szrj " Not duplicating bb %i: optimizing for size.\n",
6638fd1498Szrj header->index);
6738fd1498Szrj return false;
6838fd1498Szrj }
6938fd1498Szrj
7038fd1498Szrj gcc_assert (EDGE_COUNT (header->succs) > 0);
7138fd1498Szrj if (single_succ_p (header))
7238fd1498Szrj {
7338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
7438fd1498Szrj fprintf (dump_file,
7538fd1498Szrj " Not duplicating bb %i: it is single succ.\n",
7638fd1498Szrj header->index);
7738fd1498Szrj return false;
7838fd1498Szrj }
7938fd1498Szrj
8038fd1498Szrj if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest)
8138fd1498Szrj && flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 1)->dest))
8238fd1498Szrj {
8338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
8438fd1498Szrj fprintf (dump_file,
8538fd1498Szrj " Not duplicating bb %i: both sucessors are in loop.\n",
8638fd1498Szrj loop->num);
8738fd1498Szrj return false;
8838fd1498Szrj }
8938fd1498Szrj
9038fd1498Szrj /* If this is not the original loop header, we want it to have just
9138fd1498Szrj one predecessor in order to match the && pattern. */
9238fd1498Szrj if (header != loop->header && !single_pred_p (header))
9338fd1498Szrj {
9438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
9538fd1498Szrj fprintf (dump_file,
9638fd1498Szrj " Not duplicating bb %i: it has mutiple predecestors.\n",
9738fd1498Szrj header->index);
9838fd1498Szrj return false;
9938fd1498Szrj }
10038fd1498Szrj
10138fd1498Szrj last = last_stmt (header);
10238fd1498Szrj if (gimple_code (last) != GIMPLE_COND)
10338fd1498Szrj {
10438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
10538fd1498Szrj fprintf (dump_file,
10638fd1498Szrj " Not duplicating bb %i: it does not end by conditional.\n",
10738fd1498Szrj header->index);
10838fd1498Szrj return false;
10938fd1498Szrj }
11038fd1498Szrj
11138fd1498Szrj /* Count number of instructions and punt on calls. */
11238fd1498Szrj for (bsi = gsi_start_bb (header); !gsi_end_p (bsi); gsi_next (&bsi))
11338fd1498Szrj {
11438fd1498Szrj last = gsi_stmt (bsi);
11538fd1498Szrj
11638fd1498Szrj if (gimple_code (last) == GIMPLE_LABEL)
11738fd1498Szrj continue;
11838fd1498Szrj
11938fd1498Szrj if (is_gimple_debug (last))
12038fd1498Szrj continue;
12138fd1498Szrj
12238fd1498Szrj if (gimple_code (last) == GIMPLE_CALL
12338fd1498Szrj && (!gimple_inexpensive_call_p (as_a <gcall *> (last))
12438fd1498Szrj /* IFN_LOOP_DIST_ALIAS means that inner loop is distributed
12538fd1498Szrj at current loop's header. Don't copy in this case. */
12638fd1498Szrj || gimple_call_internal_p (last, IFN_LOOP_DIST_ALIAS)))
12738fd1498Szrj {
12838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
12938fd1498Szrj fprintf (dump_file,
13038fd1498Szrj " Not duplicating bb %i: it contains call.\n",
13138fd1498Szrj header->index);
13238fd1498Szrj return false;
13338fd1498Szrj }
13438fd1498Szrj
13538fd1498Szrj *limit -= estimate_num_insns (last, &eni_size_weights);
13638fd1498Szrj if (*limit < 0)
13738fd1498Szrj {
13838fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
13938fd1498Szrj fprintf (dump_file,
14038fd1498Szrj " Not duplicating bb %i contains too many insns.\n",
14138fd1498Szrj header->index);
14238fd1498Szrj return false;
14338fd1498Szrj }
14438fd1498Szrj }
14538fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
14638fd1498Szrj fprintf (dump_file, " Will duplicate bb %i\n", header->index);
14738fd1498Szrj return true;
14838fd1498Szrj }
14938fd1498Szrj
15038fd1498Szrj /* Checks whether LOOP is a do-while style loop. */
15138fd1498Szrj
15238fd1498Szrj static bool
do_while_loop_p(struct loop * loop)15338fd1498Szrj do_while_loop_p (struct loop *loop)
15438fd1498Szrj {
15538fd1498Szrj gimple *stmt = last_stmt (loop->latch);
15638fd1498Szrj
15738fd1498Szrj /* If the latch of the loop is not empty, it is not a do-while loop. */
15838fd1498Szrj if (stmt
15938fd1498Szrj && gimple_code (stmt) != GIMPLE_LABEL)
16038fd1498Szrj {
16138fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
16238fd1498Szrj fprintf (dump_file,
16338fd1498Szrj "Loop %i is not do-while loop: latch is not empty.\n",
16438fd1498Szrj loop->num);
16538fd1498Szrj return false;
16638fd1498Szrj }
16738fd1498Szrj
16838fd1498Szrj /* If the header contains just a condition, it is not a do-while loop. */
16938fd1498Szrj stmt = last_and_only_stmt (loop->header);
17038fd1498Szrj if (stmt
17138fd1498Szrj && gimple_code (stmt) == GIMPLE_COND)
17238fd1498Szrj {
17338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
17438fd1498Szrj fprintf (dump_file,
17538fd1498Szrj "Loop %i is not do-while loop: "
17638fd1498Szrj "header contains just condition.\n", loop->num);
17738fd1498Szrj return false;
17838fd1498Szrj }
17938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
18038fd1498Szrj fprintf (dump_file, "Loop %i is do-while loop\n", loop->num);
18138fd1498Szrj
18238fd1498Szrj return true;
18338fd1498Szrj }
18438fd1498Szrj
18538fd1498Szrj namespace {
18638fd1498Szrj
18738fd1498Szrj /* Common superclass for both header-copying phases. */
18838fd1498Szrj class ch_base : public gimple_opt_pass
18938fd1498Szrj {
19038fd1498Szrj protected:
ch_base(pass_data data,gcc::context * ctxt)19138fd1498Szrj ch_base (pass_data data, gcc::context *ctxt)
19238fd1498Szrj : gimple_opt_pass (data, ctxt)
19338fd1498Szrj {}
19438fd1498Szrj
19538fd1498Szrj /* Copies headers of all loops in FUN for which process_loop_p is true. */
19638fd1498Szrj unsigned int copy_headers (function *fun);
19738fd1498Szrj
19838fd1498Szrj /* Return true to copy headers of LOOP or false to skip. */
19938fd1498Szrj virtual bool process_loop_p (struct loop *loop) = 0;
20038fd1498Szrj };
20138fd1498Szrj
20238fd1498Szrj const pass_data pass_data_ch =
20338fd1498Szrj {
20438fd1498Szrj GIMPLE_PASS, /* type */
20538fd1498Szrj "ch", /* name */
20638fd1498Szrj OPTGROUP_LOOP, /* optinfo_flags */
20738fd1498Szrj TV_TREE_CH, /* tv_id */
20838fd1498Szrj ( PROP_cfg | PROP_ssa ), /* properties_required */
20938fd1498Szrj 0, /* properties_provided */
21038fd1498Szrj 0, /* properties_destroyed */
21138fd1498Szrj 0, /* todo_flags_start */
21238fd1498Szrj 0, /* todo_flags_finish */
21338fd1498Szrj };
21438fd1498Szrj
21538fd1498Szrj class pass_ch : public ch_base
21638fd1498Szrj {
21738fd1498Szrj public:
pass_ch(gcc::context * ctxt)21838fd1498Szrj pass_ch (gcc::context *ctxt)
21938fd1498Szrj : ch_base (pass_data_ch, ctxt)
22038fd1498Szrj {}
22138fd1498Szrj
22238fd1498Szrj /* opt_pass methods: */
gate(function *)22338fd1498Szrj virtual bool gate (function *) { return flag_tree_ch != 0; }
22438fd1498Szrj
22538fd1498Szrj /* Initialize and finalize loop structures, copying headers inbetween. */
22638fd1498Szrj virtual unsigned int execute (function *);
22738fd1498Szrj
clone()22838fd1498Szrj opt_pass * clone () { return new pass_ch (m_ctxt); }
22938fd1498Szrj
23038fd1498Szrj protected:
23138fd1498Szrj /* ch_base method: */
23238fd1498Szrj virtual bool process_loop_p (struct loop *loop);
23338fd1498Szrj }; // class pass_ch
23438fd1498Szrj
23538fd1498Szrj const pass_data pass_data_ch_vect =
23638fd1498Szrj {
23738fd1498Szrj GIMPLE_PASS, /* type */
23838fd1498Szrj "ch_vect", /* name */
23938fd1498Szrj OPTGROUP_LOOP, /* optinfo_flags */
24038fd1498Szrj TV_TREE_CH, /* tv_id */
24138fd1498Szrj ( PROP_cfg | PROP_ssa ), /* properties_required */
24238fd1498Szrj 0, /* properties_provided */
24338fd1498Szrj 0, /* properties_destroyed */
24438fd1498Szrj 0, /* todo_flags_start */
24538fd1498Szrj 0, /* todo_flags_finish */
24638fd1498Szrj };
24738fd1498Szrj
24838fd1498Szrj /* This is a more aggressive version of the same pass, designed to run just
24938fd1498Szrj before if-conversion and vectorization, to put more loops into the form
25038fd1498Szrj required for those phases. */
25138fd1498Szrj class pass_ch_vect : public ch_base
25238fd1498Szrj {
25338fd1498Szrj public:
pass_ch_vect(gcc::context * ctxt)25438fd1498Szrj pass_ch_vect (gcc::context *ctxt)
25538fd1498Szrj : ch_base (pass_data_ch_vect, ctxt)
25638fd1498Szrj {}
25738fd1498Szrj
25838fd1498Szrj /* opt_pass methods: */
gate(function * fun)25938fd1498Szrj virtual bool gate (function *fun)
26038fd1498Szrj {
26138fd1498Szrj return flag_tree_ch != 0
26238fd1498Szrj && (flag_tree_loop_vectorize != 0 || fun->has_force_vectorize_loops);
26338fd1498Szrj }
26438fd1498Szrj
26538fd1498Szrj /* Just copy headers, no initialization/finalization of loop structures. */
26638fd1498Szrj virtual unsigned int execute (function *);
26738fd1498Szrj
26838fd1498Szrj protected:
26938fd1498Szrj /* ch_base method: */
27038fd1498Szrj virtual bool process_loop_p (struct loop *loop);
27138fd1498Szrj }; // class pass_ch_vect
27238fd1498Szrj
27338fd1498Szrj /* For all loops, copy the condition at the end of the loop body in front
27438fd1498Szrj of the loop. This is beneficial since it increases efficiency of
27538fd1498Szrj code motion optimizations. It also saves one jump on entry to the loop. */
27638fd1498Szrj
27738fd1498Szrj unsigned int
copy_headers(function * fun)27838fd1498Szrj ch_base::copy_headers (function *fun)
27938fd1498Szrj {
28038fd1498Szrj struct loop *loop;
28138fd1498Szrj basic_block header;
28238fd1498Szrj edge exit, entry;
28338fd1498Szrj basic_block *bbs, *copied_bbs;
28438fd1498Szrj unsigned n_bbs;
28538fd1498Szrj unsigned bbs_size;
28638fd1498Szrj bool changed = false;
28738fd1498Szrj
28838fd1498Szrj if (number_of_loops (fun) <= 1)
28938fd1498Szrj return 0;
29038fd1498Szrj
29138fd1498Szrj bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (fun));
29238fd1498Szrj copied_bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (fun));
29338fd1498Szrj bbs_size = n_basic_blocks_for_fn (fun);
29438fd1498Szrj
29538fd1498Szrj FOR_EACH_LOOP (loop, 0)
29638fd1498Szrj {
29738fd1498Szrj int initial_limit = PARAM_VALUE (PARAM_MAX_LOOP_HEADER_INSNS);
29838fd1498Szrj int remaining_limit = initial_limit;
29938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
30038fd1498Szrj fprintf (dump_file,
30138fd1498Szrj "Analyzing loop %i\n", loop->num);
30238fd1498Szrj
30338fd1498Szrj header = loop->header;
30438fd1498Szrj
30538fd1498Szrj /* If the loop is already a do-while style one (either because it was
30638fd1498Szrj written as such, or because jump threading transformed it into one),
30738fd1498Szrj we might be in fact peeling the first iteration of the loop. This
30838fd1498Szrj in general is not a good idea. */
30938fd1498Szrj if (!process_loop_p (loop))
31038fd1498Szrj continue;
31138fd1498Szrj
31238fd1498Szrj /* Iterate the header copying up to limit; this takes care of the cases
31338fd1498Szrj like while (a && b) {...}, where we want to have both of the conditions
31438fd1498Szrj copied. TODO -- handle while (a || b) - like cases, by not requiring
31538fd1498Szrj the header to have just a single successor and copying up to
31638fd1498Szrj postdominator. */
31738fd1498Szrj
31838fd1498Szrj exit = NULL;
31938fd1498Szrj n_bbs = 0;
32038fd1498Szrj while (should_duplicate_loop_header_p (header, loop, &remaining_limit))
32138fd1498Szrj {
32238fd1498Szrj /* Find a successor of header that is inside a loop; i.e. the new
32338fd1498Szrj header after the condition is copied. */
32438fd1498Szrj if (flow_bb_inside_loop_p (loop, EDGE_SUCC (header, 0)->dest))
32538fd1498Szrj exit = EDGE_SUCC (header, 0);
32638fd1498Szrj else
32738fd1498Szrj exit = EDGE_SUCC (header, 1);
32838fd1498Szrj bbs[n_bbs++] = header;
32938fd1498Szrj gcc_assert (bbs_size > n_bbs);
33038fd1498Szrj header = exit->dest;
33138fd1498Szrj }
33238fd1498Szrj
33338fd1498Szrj if (!exit)
33438fd1498Szrj continue;
33538fd1498Szrj
33638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
33738fd1498Szrj fprintf (dump_file,
33838fd1498Szrj "Duplicating header of the loop %d up to edge %d->%d,"
33938fd1498Szrj " %i insns.\n",
34038fd1498Szrj loop->num, exit->src->index, exit->dest->index,
34138fd1498Szrj initial_limit - remaining_limit);
34238fd1498Szrj
34338fd1498Szrj /* Ensure that the header will have just the latch as a predecessor
34438fd1498Szrj inside the loop. */
34538fd1498Szrj if (!single_pred_p (exit->dest))
34638fd1498Szrj exit = single_pred_edge (split_edge (exit));
34738fd1498Szrj
34838fd1498Szrj entry = loop_preheader_edge (loop);
34938fd1498Szrj
35038fd1498Szrj propagate_threaded_block_debug_into (exit->dest, entry->dest);
35138fd1498Szrj if (!gimple_duplicate_sese_region (entry, exit, bbs, n_bbs, copied_bbs,
35238fd1498Szrj true))
35338fd1498Szrj {
35438fd1498Szrj fprintf (dump_file, "Duplication failed.\n");
35538fd1498Szrj continue;
35638fd1498Szrj }
35738fd1498Szrj
35838fd1498Szrj /* If the loop has the form "for (i = j; i < j + 10; i++)" then
35938fd1498Szrj this copying can introduce a case where we rely on undefined
36038fd1498Szrj signed overflow to eliminate the preheader condition, because
36138fd1498Szrj we assume that "j < j + 10" is true. We don't want to warn
36238fd1498Szrj about that case for -Wstrict-overflow, because in general we
36338fd1498Szrj don't warn about overflow involving loops. Prevent the
36438fd1498Szrj warning by setting the no_warning flag in the condition. */
36538fd1498Szrj if (warn_strict_overflow > 0)
36638fd1498Szrj {
36738fd1498Szrj unsigned int i;
36838fd1498Szrj
36938fd1498Szrj for (i = 0; i < n_bbs; ++i)
37038fd1498Szrj {
37138fd1498Szrj gimple_stmt_iterator bsi;
37238fd1498Szrj
37338fd1498Szrj for (bsi = gsi_start_bb (copied_bbs[i]);
37438fd1498Szrj !gsi_end_p (bsi);
37538fd1498Szrj gsi_next (&bsi))
37638fd1498Szrj {
37738fd1498Szrj gimple *stmt = gsi_stmt (bsi);
37838fd1498Szrj if (gimple_code (stmt) == GIMPLE_COND)
379*e215fc28Szrj {
380*e215fc28Szrj tree lhs = gimple_cond_lhs (stmt);
381*e215fc28Szrj if (gimple_cond_code (stmt) != EQ_EXPR
382*e215fc28Szrj && gimple_cond_code (stmt) != NE_EXPR
383*e215fc28Szrj && INTEGRAL_TYPE_P (TREE_TYPE (lhs))
384*e215fc28Szrj && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (lhs)))
38538fd1498Szrj gimple_set_no_warning (stmt, true);
386*e215fc28Szrj }
38738fd1498Szrj else if (is_gimple_assign (stmt))
38838fd1498Szrj {
38938fd1498Szrj enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
390*e215fc28Szrj tree rhs1 = gimple_assign_rhs1 (stmt);
391*e215fc28Szrj if (TREE_CODE_CLASS (rhs_code) == tcc_comparison
392*e215fc28Szrj && rhs_code != EQ_EXPR
393*e215fc28Szrj && rhs_code != NE_EXPR
394*e215fc28Szrj && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
395*e215fc28Szrj && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (rhs1)))
39638fd1498Szrj gimple_set_no_warning (stmt, true);
39738fd1498Szrj }
39838fd1498Szrj }
39938fd1498Szrj }
40038fd1498Szrj }
40138fd1498Szrj
40238fd1498Szrj /* Ensure that the latch and the preheader is simple (we know that they
40338fd1498Szrj are not now, since there was the loop exit condition. */
40438fd1498Szrj split_edge (loop_preheader_edge (loop));
40538fd1498Szrj split_edge (loop_latch_edge (loop));
40638fd1498Szrj
40738fd1498Szrj changed = true;
40838fd1498Szrj }
40938fd1498Szrj
41038fd1498Szrj if (changed)
41138fd1498Szrj update_ssa (TODO_update_ssa);
41238fd1498Szrj free (bbs);
41338fd1498Szrj free (copied_bbs);
41438fd1498Szrj
41538fd1498Szrj return changed ? TODO_cleanup_cfg : 0;
41638fd1498Szrj }
41738fd1498Szrj
41838fd1498Szrj /* Initialize the loop structures we need, and finalize after. */
41938fd1498Szrj
42038fd1498Szrj unsigned int
execute(function * fun)42138fd1498Szrj pass_ch::execute (function *fun)
42238fd1498Szrj {
42338fd1498Szrj loop_optimizer_init (LOOPS_HAVE_PREHEADERS
42438fd1498Szrj | LOOPS_HAVE_SIMPLE_LATCHES);
42538fd1498Szrj
42638fd1498Szrj unsigned int res = copy_headers (fun);
42738fd1498Szrj
42838fd1498Szrj loop_optimizer_finalize ();
42938fd1498Szrj return res;
43038fd1498Szrj }
43138fd1498Szrj
43238fd1498Szrj /* Assume an earlier phase has already initialized all the loop structures that
43338fd1498Szrj we need here (and perhaps others too), and that these will be finalized by
43438fd1498Szrj a later phase. */
43538fd1498Szrj
43638fd1498Szrj unsigned int
execute(function * fun)43738fd1498Szrj pass_ch_vect::execute (function *fun)
43838fd1498Szrj {
43938fd1498Szrj return copy_headers (fun);
44038fd1498Szrj }
44138fd1498Szrj
44238fd1498Szrj /* Apply header copying according to a very simple test of do-while shape. */
44338fd1498Szrj
44438fd1498Szrj bool
process_loop_p(struct loop * loop)44538fd1498Szrj pass_ch::process_loop_p (struct loop *loop)
44638fd1498Szrj {
44738fd1498Szrj return !do_while_loop_p (loop);
44838fd1498Szrj }
44938fd1498Szrj
45038fd1498Szrj /* Apply header-copying to loops where we might enable vectorization. */
45138fd1498Szrj
45238fd1498Szrj bool
process_loop_p(struct loop * loop)45338fd1498Szrj pass_ch_vect::process_loop_p (struct loop *loop)
45438fd1498Szrj {
45538fd1498Szrj if (!flag_tree_loop_vectorize && !loop->force_vectorize)
45638fd1498Szrj return false;
45738fd1498Szrj
45838fd1498Szrj if (loop->dont_vectorize)
45938fd1498Szrj return false;
46038fd1498Szrj
46138fd1498Szrj if (!do_while_loop_p (loop))
46238fd1498Szrj return true;
46338fd1498Szrj
46438fd1498Szrj /* The vectorizer won't handle anything with multiple exits, so skip. */
46538fd1498Szrj edge exit = single_exit (loop);
46638fd1498Szrj if (!exit)
46738fd1498Szrj return false;
46838fd1498Szrj
46938fd1498Szrj /* Copy headers iff there looks to be code in the loop after the exit block,
47038fd1498Szrj i.e. the exit block has an edge to another block (besides the latch,
47138fd1498Szrj which should be empty). */
47238fd1498Szrj edge_iterator ei;
47338fd1498Szrj edge e;
47438fd1498Szrj FOR_EACH_EDGE (e, ei, exit->src->succs)
47538fd1498Szrj if (!loop_exit_edge_p (loop, e)
47638fd1498Szrj && e->dest != loop->header
47738fd1498Szrj && e->dest != loop->latch)
47838fd1498Szrj return true;
47938fd1498Szrj
48038fd1498Szrj return false;
48138fd1498Szrj }
48238fd1498Szrj
48338fd1498Szrj } // anon namespace
48438fd1498Szrj
48538fd1498Szrj gimple_opt_pass *
make_pass_ch_vect(gcc::context * ctxt)48638fd1498Szrj make_pass_ch_vect (gcc::context *ctxt)
48738fd1498Szrj {
48838fd1498Szrj return new pass_ch_vect (ctxt);
48938fd1498Szrj }
49038fd1498Szrj
49138fd1498Szrj gimple_opt_pass *
make_pass_ch(gcc::context * ctxt)49238fd1498Szrj make_pass_ch (gcc::context *ctxt)
49338fd1498Szrj {
49438fd1498Szrj return new pass_ch (ctxt);
49538fd1498Szrj }
496