xref: /dflybsd-src/contrib/gcc-8.0/gcc/tree-ssa-loop-ch.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
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