tree-if-conv.c (tree-ssa-loop.h): Include header file.

* tree-if-conv.c (tree-ssa-loop.h): Include header file.
	(tree-ssa-loop-niter.h): Ditto.
	(idx_within_array_bound, ref_within_array_bound): New functions.
	(ifcvt_memrefs_wont_trap): Check if array ref is within bound.
	Factor out check on writable base object to ...
	(base_object_writable): ... here.

	gcc/testsuite/
	* gcc.dg/tree-ssa/ifc-9.c: New test.
	* gcc.dg/tree-ssa/ifc-10.c: New test.
	* gcc.dg/tree-ssa/ifc-11.c: New test.
	* gcc.dg/tree-ssa/ifc-12.c: New test.
	* gcc.dg/vect/pr61194.c: Remove XFAIL.
	* gcc.dg/vect/vect-23.c: Remove XFAIL.
	* gcc.dg/vect/vect-mask-store-move-1.c: Revise test check.

From-SVN: r236026
This commit is contained in:
Bin Cheng 2016-05-09 11:44:03 +00:00 committed by Bin Cheng
parent fb334765e2
commit 18caa34eb2
10 changed files with 223 additions and 14 deletions

View File

@ -1,3 +1,12 @@
2016-05-09 Bin Cheng <bin.cheng@arm.com>
* tree-if-conv.c (tree-ssa-loop.h): Include header file.
(tree-ssa-loop-niter.h): Ditto.
(idx_within_array_bound, ref_within_array_bound): New functions.
(ifcvt_memrefs_wont_trap): Check if array ref is within bound.
Factor out check on writable base object to ...
(base_object_writable): ... here.
2016-05-09 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* config/arm/arm.md (probe_stack): Add modes to set source

View File

@ -1,3 +1,13 @@
2016-05-09 Bin Cheng <bin.cheng@arm.com>
* gcc.dg/tree-ssa/ifc-9.c: New test.
* gcc.dg/tree-ssa/ifc-10.c: New test.
* gcc.dg/tree-ssa/ifc-11.c: New test.
* gcc.dg/tree-ssa/ifc-12.c: New test.
* gcc.dg/vect/pr61194.c: Remove XFAIL.
* gcc.dg/vect/vect-23.c: Remove XFAIL.
* gcc.dg/vect/vect-mask-store-move-1.c: Revise test check.
2016-05-09 Richard Biener <rguenther@suse.de>
PR fortran/70937

View File

@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-Ofast -fdump-tree-ifcvt-stats" } */
/* { dg-require-visibility "" } */
int b[256] = {0}, y;
void bar (int *);
int foo (int x, int n)
{
int i;
int a[128];
for (i = 0; i < n; i++)
{
a[i] = i;
if (x > i)
b[i] = y;
}
bar (a);
return 0;
}
/* { dg-final { scan-tree-dump-times "Applying if-conversion" 1 "ifcvt" } } */

View File

@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-Ofast -fdump-tree-ifcvt-stats" } */
/* { dg-require-visibility "" } */
int a[1024] = {0.0};
int b[1024] = {0.0};
int c[1024] = {0.0};
int foo (float *x)
{
int i = 0;
for (i = 0; i < 1024; i++)
{
c[i] = (x[i] > 0.0) ? a[i] : b[i];
}
return 0;
}
/* { dg-final { scan-tree-dump-times "Applying if-conversion" 1 "ifcvt" } } */

View File

@ -0,0 +1,25 @@
/* { dg-do compile } */
/* { dg-options "-Ofast -fdump-tree-ifcvt-stats" } */
/* { dg-require-visibility "" } */
struct st
{
int a[1024];
int b[1024];
};
struct st s = {0};
int foo (int x)
{
int i;
struct st *p = &s;
for (i = 0; i < 1024; i++)
{
if (x > i)
p->a[i] = p->b[i];
}
return 0;
}
/* { dg-final { scan-tree-dump-times "Applying if-conversion" 1 "ifcvt" } } */

View File

@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-Ofast -fdump-tree-ifcvt-stats" } */
/* { dg-require-visibility "" } */
extern int b[256], y;
void bar (int *, int);
int foo (int x, int n)
{
int i;
int a[128];
for (i = 0; i < n; i++)
{
a[i] = i;
if (x > i)
y = b[i];
}
bar (a, y);
return 0;
}
/* { dg-final { scan-tree-dump-times "Applying if-conversion" 1 "ifcvt" } } */

View File

@ -38,4 +38,4 @@ int main()
return 0;
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */

View File

@ -123,5 +123,5 @@ int main (void)
return main1 ();
}
/* { dg-final { scan-tree-dump-times "vectorized 3 loops" 1 "vect" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "vectorized 3 loops" 1 "vect" } } */
/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 0 "vect" } } */

View File

@ -15,4 +15,4 @@ void foo (int n)
}
}
/* { dg-final { scan-tree-dump-times "Move stmt to created bb" 6 "vect" { target { i?86-*-* x86_64-*-* } } } } */
/* { dg-final { scan-tree-dump-times "Move stmt to created bb" 4 "vect" { target { i?86-*-* x86_64-*-* } } } } */

View File

@ -106,6 +106,8 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h"
#include "tree-data-ref.h"
#include "tree-scalar-evolution.h"
#include "tree-ssa-loop.h"
#include "tree-ssa-loop-niter.h"
#include "tree-ssa-loop-ivopts.h"
#include "tree-ssa-address.h"
#include "dbgcnt.h"
@ -718,6 +720,105 @@ hash_memrefs_baserefs_and_store_DRs_read_written_info (data_reference_p a)
}
}
/* Return TRUE if can prove the index IDX of an array reference REF is
within array bound. Return false otherwise. */
static bool
idx_within_array_bound (tree ref, tree *idx, void *dta)
{
bool overflow;
widest_int niter, valid_niter, delta, wi_step;
tree ev, init, step;
tree low, high;
struct loop *loop = (struct loop*) dta;
/* Only support within-bound access for array references. */
if (TREE_CODE (ref) != ARRAY_REF)
return false;
/* For arrays at the end of the structure, we are not guaranteed that they
do not really extend over their declared size. However, for arrays of
size greater than one, this is unlikely to be intended. */
if (array_at_struct_end_p (ref))
return false;
ev = analyze_scalar_evolution (loop, *idx);
ev = instantiate_parameters (loop, ev);
init = initial_condition (ev);
step = evolution_part_in_loop_num (ev, loop->num);
if (!init || TREE_CODE (init) != INTEGER_CST
|| (step && TREE_CODE (step) != INTEGER_CST))
return false;
low = array_ref_low_bound (ref);
high = array_ref_up_bound (ref);
/* The case of nonconstant bounds could be handled, but it would be
complicated. */
if (TREE_CODE (low) != INTEGER_CST
|| !high || TREE_CODE (high) != INTEGER_CST)
return false;
/* Check if the intial idx is within bound. */
if (wi::to_widest (init) < wi::to_widest (low)
|| wi::to_widest (init) > wi::to_widest (high))
return false;
/* The idx is always within bound. */
if (!step || integer_zerop (step))
return true;
if (!max_loop_iterations (loop, &niter))
return false;
if (wi::to_widest (step) < 0)
{
delta = wi::to_widest (init) - wi::to_widest (low);
wi_step = -wi::to_widest (step);
}
else
{
delta = wi::to_widest (high) - wi::to_widest (init);
wi_step = wi::to_widest (step);
}
valid_niter = wi::div_floor (delta, wi_step, SIGNED, &overflow);
/* The iteration space of idx is within array bound. */
if (!overflow && niter <= valid_niter)
return true;
return false;
}
/* Return TRUE if ref is a within bound array reference. */
static bool
ref_within_array_bound (gimple *stmt, tree ref)
{
struct loop *loop = loop_containing_stmt (stmt);
gcc_assert (loop != NULL);
return for_each_index (&ref, idx_within_array_bound, loop);
}
/* Given a memory reference expression T, return TRUE if base object
it refers to is writable. The base object of a memory reference
is the main object being referenced, which is returned by function
get_base_address. */
static bool
base_object_writable (tree ref)
{
tree base_tree = get_base_address (ref);
return (base_tree
&& DECL_P (base_tree)
&& decl_binds_to_current_def_p (base_tree)
&& !TREE_READONLY (base_tree));
}
/* Return true when the memory references of STMT won't trap in the
if-converted code. There are two things that we have to check for:
@ -765,8 +866,13 @@ ifcvt_memrefs_wont_trap (gimple *stmt, vec<data_reference_p> drs)
if (DR_W_UNCONDITIONALLY (*master_dr))
return true;
/* If a is unconditionally accessed then ... */
if (DR_RW_UNCONDITIONALLY (*master_dr))
/* If a is unconditionally accessed then ...
Even a is conditional access, we can treat it as an unconditional
one if it's an array reference and all its index are within array
bound. */
if (DR_RW_UNCONDITIONALLY (*master_dr)
|| ref_within_array_bound (stmt, DR_REF (a)))
{
/* an unconditional read won't trap. */
if (DR_IS_READ (a))
@ -777,16 +883,11 @@ ifcvt_memrefs_wont_trap (gimple *stmt, vec<data_reference_p> drs)
if (base_master_dr
&& DR_BASE_W_UNCONDITIONALLY (*base_master_dr))
return PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES);
else
{
/* or the base is know to be not readonly. */
tree base_tree = get_base_address (DR_REF (a));
if (DECL_P (base_tree)
&& decl_binds_to_current_def_p (base_tree)
&& ! TREE_READONLY (base_tree))
return PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES);
}
/* or the base is known to be not readonly. */
else if (base_object_writable (DR_REF (a)))
return PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES);
}
return false;
}