tree-pass.h (make_pass_ch_vect): New.

gcc/:

	* tree-pass.h (make_pass_ch_vect): New.
	* passes.def: Add pass_ch_vect just before pass_if_conversion.

	* tree-ssa-loop-ch.c (ch_base, pass_ch_vect, pass_data_ch_vect,
	pass_ch::process_loop_p, pass_ch_vect::process_loop_p,
	make_pass_ch_vect): New.
	(pass_ch): Extend ch_base.

	(pass_ch::execute): Move all but loop_optimizer_init/finalize to...
	(ch_base::copy_headers): ...here.

gcc/testsuite/:

	* gcc.dg/vect/vect-strided-a-u16-i4.c (main1): Narrow scope of x,y,z,w.
	* gcc.dg/vect/vect-ifcvt-11.c: New testcase.

From-SVN: r225311
This commit is contained in:
Alan Lawrence 2015-07-02 11:47:31 +00:00 committed by Alan Lawrence
parent 5fa79de857
commit 4f9a2b4e88
7 changed files with 196 additions and 16 deletions

View File

@ -1,3 +1,16 @@
2015-07-02 Alan Lawrence <alan.lawrence@arm.com>
* tree-pass.h (make_pass_ch_vect): New.
* passes.def: Add pass_ch_vect just before pass_if_conversion.
* tree-ssa-loop-ch.c (ch_base, pass_ch_vect, pass_data_ch_vect,
pass_ch::process_loop_p, pass_ch_vect::process_loop_p,
make_pass_ch_vect): New.
(pass_ch): Extend ch_base.
(pass_ch::execute): Move all but loop_optimizer_init/finalize to...
(ch_base::copy_headers): ...here.
2015-07-02 Richard Biener <rguenther@suse.de> 2015-07-02 Richard Biener <rguenther@suse.de>
* builtins.c (get_pointer_alignment_1): Handle POINTER_PLUS_EXPR. * builtins.c (get_pointer_alignment_1): Handle POINTER_PLUS_EXPR.

View File

@ -247,6 +247,7 @@ along with GCC; see the file COPYING3. If not see
PUSH_INSERT_PASSES_WITHIN (pass_parallelize_loops) PUSH_INSERT_PASSES_WITHIN (pass_parallelize_loops)
NEXT_PASS (pass_expand_omp_ssa); NEXT_PASS (pass_expand_omp_ssa);
POP_INSERT_PASSES () POP_INSERT_PASSES ()
NEXT_PASS (pass_ch_vect);
NEXT_PASS (pass_if_conversion); NEXT_PASS (pass_if_conversion);
/* pass_vectorize must immediately follow pass_if_conversion. /* pass_vectorize must immediately follow pass_if_conversion.
Please do not add any other passes in between. */ Please do not add any other passes in between. */

View File

@ -1,3 +1,8 @@
2015-07-02 Alan Lawrence <alan.lawrence@arm.com>
* gcc.dg/vect/vect-strided-a-u16-i4.c (main1): Narrow scope of x,y,z,w.
* gcc.dg/vect/vect-ifcvt-11.c: New testcase.
2015-07-02 Richard Biener <rguenther@suse.de> 2015-07-02 Richard Biener <rguenther@suse.de>
PR testsuite/66719 PR testsuite/66719

View File

@ -0,0 +1,36 @@
/* { dg-require-effective-target vect_condition } */
/* { dg-require-effective-target vect_int } */
#include "tree-vect.h"
#define N 16
extern void abort (void);
int A[N] = {36, 39, 42, 45, 43, 32, 21, 12, 23, 34, 45, 56, 67, 78, 81, 11};
int B[N] = {144,195,210,225,172,128,105,60, 92, 136,225,280,268,390,324,55};
__attribute__((noinline))
void foo ()
{
for (int i = 0; i < N; i++)
{
int m = (A[i] & i) ? 5 : 4;
A[i] = A[i] * m;
}
}
int main ()
{
check_vect ();
foo ();
/* check results: */
for (int i = 0; i < N; i++)
if (A[i] != B[i])
abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */

View File

@ -21,7 +21,6 @@ main1 ()
s *ptr = arr; s *ptr = arr;
s res[N]; s res[N];
int i; int i;
unsigned short x, y, z, w;
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
{ {
@ -35,6 +34,7 @@ main1 ()
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
{ {
unsigned short x, y, z, w;
x = ptr->b - ptr->a; x = ptr->b - ptr->a;
y = ptr->d - ptr->c; y = ptr->d - ptr->c;
res[i].c = x + y; res[i].c = x + y;

View File

@ -381,6 +381,7 @@ extern gimple_opt_pass *make_pass_loop_prefetch (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_iv_optimize (gcc::context *ctxt); extern gimple_opt_pass *make_pass_iv_optimize (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_tree_loop_done (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tree_loop_done (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_ch (gcc::context *ctxt); extern gimple_opt_pass *make_pass_ch (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_ch_vect (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_ccp (gcc::context *ctxt); extern gimple_opt_pass *make_pass_ccp (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_phi_only_cprop (gcc::context *ctxt); extern gimple_opt_pass *make_pass_phi_only_cprop (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_build_ssa (gcc::context *ctxt); extern gimple_opt_pass *make_pass_build_ssa (gcc::context *ctxt);

View File

@ -135,12 +135,23 @@ do_while_loop_p (struct loop *loop)
return true; return true;
} }
/* For all loops, copy the condition at the end of the loop body in front
of the loop. This is beneficial since it increases efficiency of
code motion optimizations. It also saves one jump on entry to the loop. */
namespace { namespace {
/* Common superclass for both header-copying phases. */
class ch_base : public gimple_opt_pass
{
protected:
ch_base (pass_data data, gcc::context *ctxt)
: gimple_opt_pass (data, ctxt)
{}
/* Copies headers of all loops in FUN for which process_loop_p is true. */
unsigned int copy_headers (function *fun);
/* Return true to copy headers of LOOP or false to skip. */
virtual bool process_loop_p (struct loop *loop) = 0;
};
const pass_data pass_data_ch = const pass_data pass_data_ch =
{ {
GIMPLE_PASS, /* type */ GIMPLE_PASS, /* type */
@ -154,21 +165,68 @@ const pass_data pass_data_ch =
0, /* todo_flags_finish */ 0, /* todo_flags_finish */
}; };
class pass_ch : public gimple_opt_pass class pass_ch : public ch_base
{ {
public: public:
pass_ch (gcc::context *ctxt) pass_ch (gcc::context *ctxt)
: gimple_opt_pass (pass_data_ch, ctxt) : ch_base (pass_data_ch, ctxt)
{} {}
/* opt_pass methods: */ /* opt_pass methods: */
virtual bool gate (function *) { return flag_tree_ch != 0; } virtual bool gate (function *) { return flag_tree_ch != 0; }
/* Initialize and finalize loop structures, copying headers inbetween. */
virtual unsigned int execute (function *); virtual unsigned int execute (function *);
protected:
/* ch_base method: */
virtual bool process_loop_p (struct loop *loop);
}; // class pass_ch }; // class pass_ch
const pass_data pass_data_ch_vect =
{
GIMPLE_PASS, /* type */
"ch_vect", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
TV_TREE_CH, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
/* This is a more aggressive version of the same pass, designed to run just
before if-conversion and vectorization, to put more loops into the form
required for those phases. */
class pass_ch_vect : public ch_base
{
public:
pass_ch_vect (gcc::context *ctxt)
: ch_base (pass_data_ch_vect, ctxt)
{}
/* opt_pass methods: */
virtual bool gate (function *fun)
{
return flag_tree_ch != 0
&& (flag_tree_loop_vectorize != 0 || fun->has_force_vectorize_loops);
}
/* Just copy headers, no initialization/finalization of loop structures. */
virtual unsigned int execute (function *);
protected:
/* ch_base method: */
virtual bool process_loop_p (struct loop *loop);
}; // class pass_ch_vect
/* For all loops, copy the condition at the end of the loop body in front
of the loop. This is beneficial since it increases efficiency of
code motion optimizations. It also saves one jump on entry to the loop. */
unsigned int unsigned int
pass_ch::execute (function *fun) ch_base::copy_headers (function *fun)
{ {
struct loop *loop; struct loop *loop;
basic_block header; basic_block header;
@ -178,13 +236,8 @@ pass_ch::execute (function *fun)
unsigned bbs_size; unsigned bbs_size;
bool changed = false; bool changed = false;
loop_optimizer_init (LOOPS_HAVE_PREHEADERS
| LOOPS_HAVE_SIMPLE_LATCHES);
if (number_of_loops (fun) <= 1) if (number_of_loops (fun) <= 1)
{
loop_optimizer_finalize ();
return 0; return 0;
}
bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (fun)); bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (fun));
copied_bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (fun)); copied_bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (fun));
@ -201,7 +254,7 @@ pass_ch::execute (function *fun)
written as such, or because jump threading transformed it into one), written as such, or because jump threading transformed it into one),
we might be in fact peeling the first iteration of the loop. This we might be in fact peeling the first iteration of the loop. This
in general is not a good idea. */ in general is not a good idea. */
if (do_while_loop_p (loop)) if (!process_loop_p (loop))
continue; continue;
/* Iterate the header copying up to limit; this takes care of the cases /* Iterate the header copying up to limit; this takes care of the cases
@ -288,16 +341,87 @@ pass_ch::execute (function *fun)
changed = true; changed = true;
} }
update_ssa (TODO_update_ssa); if (changed)
update_ssa (TODO_update_ssa);
free (bbs); free (bbs);
free (copied_bbs); free (copied_bbs);
loop_optimizer_finalize ();
return changed ? TODO_cleanup_cfg : 0; return changed ? TODO_cleanup_cfg : 0;
} }
/* Initialize the loop structures we need, and finalize after. */
unsigned int
pass_ch::execute (function *fun)
{
loop_optimizer_init (LOOPS_HAVE_PREHEADERS
| LOOPS_HAVE_SIMPLE_LATCHES);
unsigned int res = copy_headers (fun);
loop_optimizer_finalize ();
return res;
}
/* Assume an earlier phase has already initialized all the loop structures that
we need here (and perhaps others too), and that these will be finalized by
a later phase. */
unsigned int
pass_ch_vect::execute (function *fun)
{
return copy_headers (fun);
}
/* Apply header copying according to a very simple test of do-while shape. */
bool
pass_ch::process_loop_p (struct loop *loop)
{
return !do_while_loop_p (loop);
}
/* Apply header-copying to loops where we might enable vectorization. */
bool
pass_ch_vect::process_loop_p (struct loop *loop)
{
if (!flag_tree_vectorize && !loop->force_vectorize)
return false;
if (loop->dont_vectorize)
return false;
if (!do_while_loop_p (loop))
return true;
/* The vectorizer won't handle anything with multiple exits, so skip. */
edge exit = single_exit (loop);
if (!exit)
return false;
/* Copy headers iff there looks to be code in the loop after the exit block,
i.e. the exit block has an edge to another block (besides the latch,
which should be empty). */
edge_iterator ei;
edge e;
FOR_EACH_EDGE (e, ei, exit->src->succs)
if (!loop_exit_edge_p (loop, e)
&& e->dest != loop->header
&& e->dest != loop->latch)
return true;
return false;
}
} // anon namespace } // anon namespace
gimple_opt_pass *
make_pass_ch_vect (gcc::context *ctxt)
{
return new pass_ch_vect (ctxt);
}
gimple_opt_pass * gimple_opt_pass *
make_pass_ch (gcc::context *ctxt) make_pass_ch (gcc::context *ctxt)
{ {