mirror of git://gcc.gnu.org/git/gcc.git
re PR tree-optimization/56541 (vectorizaton fails in conditional assignment of a constant)
PR tree-optimization/56541 * doc/invoke.texi (@item max-tree-if-conversion-phi-args): New item. * params.def (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS): new param. * tree-if-conv.c (MAX_PHI_ARG_NUM): new macro. (any_complicated_phi): new static variable. (aggressive_if_conv): delete. (if_convertible_phi_p): support phis with more than two arguments. (if_convertible_bb_p): remvoe check on aggressive_if_conv and critical pred edges. (ifcvt_split_critical_edges): support phis with more than two arguments by checking new parameter. only split critical edges if needed. (tree_if_conversion): handle simd pragma marked loop using new local variable aggressive_if_conv. check any_complicated_phi. gcc/testsuite PR tree-optimization/56541 * gcc.dg/tree-ssa/ifc-pr56541.c: new test. * gcc.dg/vect/pr56541.c: new test. From-SVN: r235808
This commit is contained in:
parent
15526589cf
commit
1cfcd39eee
|
|
@ -1,3 +1,20 @@
|
||||||
|
2016-05-03 bin cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
PR tree-optimization/56541
|
||||||
|
* doc/invoke.texi (@item max-tree-if-conversion-phi-args): New item.
|
||||||
|
* params.def (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS): new param.
|
||||||
|
* tree-if-conv.c (MAX_PHI_ARG_NUM): new macro.
|
||||||
|
(any_complicated_phi): new static variable.
|
||||||
|
(aggressive_if_conv): delete.
|
||||||
|
(if_convertible_phi_p): support phis with more than two arguments.
|
||||||
|
(if_convertible_bb_p): remvoe check on aggressive_if_conv and
|
||||||
|
critical pred edges.
|
||||||
|
(ifcvt_split_critical_edges): support phis with more than two
|
||||||
|
arguments by checking new parameter. only split critical edges
|
||||||
|
if needed.
|
||||||
|
(tree_if_conversion): handle simd pragma marked loop using new
|
||||||
|
local variable aggressive_if_conv. check any_complicated_phi.
|
||||||
|
|
||||||
2016-05-03 Bin Cheng <bin.cheng@arm.com>
|
2016-05-03 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
* tree-ssa-loop-ivopts.c (get_computation_cost_at): Check depends_on
|
* tree-ssa-loop-ivopts.c (get_computation_cost_at): Check depends_on
|
||||||
|
|
|
||||||
|
|
@ -9020,6 +9020,10 @@ Large expressions slow the analyzer.
|
||||||
Bound on the complexity of the expressions in the scalar evolutions analyzer.
|
Bound on the complexity of the expressions in the scalar evolutions analyzer.
|
||||||
Complex expressions slow the analyzer.
|
Complex expressions slow the analyzer.
|
||||||
|
|
||||||
|
@item max-tree-if-conversion-phi-args
|
||||||
|
Maximum number of arguments in a PHI supported by TREE if conversion
|
||||||
|
unless the loop is marked with simd pragma.
|
||||||
|
|
||||||
@item vect-max-version-for-alignment-checks
|
@item vect-max-version-for-alignment-checks
|
||||||
The maximum number of run-time checks that can be performed when
|
The maximum number of run-time checks that can be performed when
|
||||||
doing loop versioning for alignment in the vectorizer.
|
doing loop versioning for alignment in the vectorizer.
|
||||||
|
|
|
||||||
|
|
@ -530,6 +530,12 @@ DEFPARAM(PARAM_SCEV_MAX_EXPR_COMPLEXITY,
|
||||||
"Bound on the complexity of the expressions in the scalar evolutions analyzer.",
|
"Bound on the complexity of the expressions in the scalar evolutions analyzer.",
|
||||||
10, 0, 0)
|
10, 0, 0)
|
||||||
|
|
||||||
|
DEFPARAM (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS,
|
||||||
|
"max-tree-if-conversion-phi-args",
|
||||||
|
"Maximum number of arguments in a PHI supported by TREE if-conversion "
|
||||||
|
"unless the loop is marked with simd pragma.",
|
||||||
|
4, 2, 0)
|
||||||
|
|
||||||
DEFPARAM(PARAM_VECT_MAX_VERSION_FOR_ALIGNMENT_CHECKS,
|
DEFPARAM(PARAM_VECT_MAX_VERSION_FOR_ALIGNMENT_CHECKS,
|
||||||
"vect-max-version-for-alignment-checks",
|
"vect-max-version-for-alignment-checks",
|
||||||
"Bound on number of runtime checks inserted by the vectorizer's loop versioning for alignment check.",
|
"Bound on number of runtime checks inserted by the vectorizer's loop versioning for alignment check.",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
2016-05-03 bin cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
PR tree-optimization/56541
|
||||||
|
* gcc.dg/tree-ssa/ifc-pr56541.c: new test.
|
||||||
|
* gcc.dg/vect/pr56541.c: new test.
|
||||||
|
|
||||||
2016-05-02 Michael Meissner <meissner@linux.vnet.ibm.com>
|
2016-05-02 Michael Meissner <meissner@linux.vnet.ibm.com>
|
||||||
|
|
||||||
* gcc.target/powerpc/float128-complex-1.c: New tests for complex
|
* gcc.target/powerpc/float128-complex-1.c: New tests for complex
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O3 -fdump-tree-ifcvt-stats" } */
|
||||||
|
|
||||||
|
float a,b,c,d;
|
||||||
|
|
||||||
|
float z[1024]; int ok[1024];
|
||||||
|
const float rBig = 150.;
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i!=1024; ++i)
|
||||||
|
{
|
||||||
|
float rR = a*z[i];
|
||||||
|
float rL = b*z[i];
|
||||||
|
float rMin = (rR<rL) ? rR : rL;
|
||||||
|
float rMax = (rR<rL) ? rL : rR;
|
||||||
|
rMin = (rMax>0) ? rMin : rBig;
|
||||||
|
rMin = (rMin>0) ? rMin : rMax;
|
||||||
|
ok[i] = rMin-c<rMax+d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-tree-dump-times "Applying if-conversion" 1 "ifcvt" } } */
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-require-effective-target vect_int } */
|
||||||
|
/* { dg-require-effective-target vect_float } */
|
||||||
|
/* { dg-require-effective-target vect_condition } */
|
||||||
|
|
||||||
|
float a,b,c,d;
|
||||||
|
|
||||||
|
float z[1024]; int ok[1024];
|
||||||
|
const float rBig = 150.;
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i!=1024; ++i)
|
||||||
|
{
|
||||||
|
float rR = a*z[i];
|
||||||
|
float rL = b*z[i];
|
||||||
|
float rMin = (rR<rL) ? rR : rL;
|
||||||
|
float rMax = (rR<rL) ? rL : rR;
|
||||||
|
rMin = (rMax>0) ? rMin : rBig;
|
||||||
|
rMin = (rMin>0) ? rMin : rMax;
|
||||||
|
ok[i] = rMin-c<rMax+d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
|
||||||
|
|
@ -114,10 +114,21 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "builtins.h"
|
#include "builtins.h"
|
||||||
#include "params.h"
|
#include "params.h"
|
||||||
|
|
||||||
|
/* Only handle PHIs with no more arguments unless we are asked to by
|
||||||
|
simd pragma. */
|
||||||
|
#define MAX_PHI_ARG_NUM \
|
||||||
|
((unsigned) PARAM_VALUE (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS))
|
||||||
|
|
||||||
/* Indicate if new load/store that needs to be predicated is introduced
|
/* Indicate if new load/store that needs to be predicated is introduced
|
||||||
during if conversion. */
|
during if conversion. */
|
||||||
static bool any_pred_load_store;
|
static bool any_pred_load_store;
|
||||||
|
|
||||||
|
/* Indicate if there are any complicated PHIs that need to be handled in
|
||||||
|
if-conversion. Complicated PHI has more than two arguments and can't
|
||||||
|
be degenerated to two arguments PHI. See more information in comment
|
||||||
|
before phi_convertible_by_degenerating_args. */
|
||||||
|
static bool any_complicated_phi;
|
||||||
|
|
||||||
/* Hash for struct innermost_loop_behavior. It depends on the user to
|
/* Hash for struct innermost_loop_behavior. It depends on the user to
|
||||||
free the memory. */
|
free the memory. */
|
||||||
|
|
||||||
|
|
@ -172,9 +183,6 @@ innermost_loop_behavior_hash::equal (const value_type &e1,
|
||||||
/* List of basic blocks in if-conversion-suitable order. */
|
/* List of basic blocks in if-conversion-suitable order. */
|
||||||
static basic_block *ifc_bbs;
|
static basic_block *ifc_bbs;
|
||||||
|
|
||||||
/* Apply more aggressive (extended) if-conversion if true. */
|
|
||||||
static bool aggressive_if_conv;
|
|
||||||
|
|
||||||
/* Hash table to store <DR's innermost loop behavior, DR> pairs. */
|
/* Hash table to store <DR's innermost loop behavior, DR> pairs. */
|
||||||
static hash_map<innermost_loop_behavior_hash,
|
static hash_map<innermost_loop_behavior_hash,
|
||||||
data_reference_p> *innermost_DR_map;
|
data_reference_p> *innermost_DR_map;
|
||||||
|
|
@ -639,13 +647,9 @@ phi_convertible_by_degenerating_args (gphi *phi)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true when PHI is if-convertible. PHI is part of loop LOOP
|
/* Return true when PHI is if-convertible. PHI is part of loop LOOP
|
||||||
and it belongs to basic block BB.
|
and it belongs to basic block BB. Note at this point, it is sure
|
||||||
|
that PHI is if-convertible. This function updates global variable
|
||||||
PHI is not if-convertible if:
|
ANY_COMPLICATED_PHI if PHI is complicated. */
|
||||||
- it has more than 2 arguments.
|
|
||||||
|
|
||||||
When the aggressive_if_conv is set, PHI can have more than
|
|
||||||
two arguments. */
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi)
|
if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi)
|
||||||
|
|
@ -656,17 +660,10 @@ if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi)
|
||||||
print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
|
print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bb != loop->header)
|
if (bb != loop->header
|
||||||
{
|
&& gimple_phi_num_args (phi) > 2
|
||||||
if (gimple_phi_num_args (phi) > 2
|
|
||||||
&& !aggressive_if_conv
|
|
||||||
&& !phi_convertible_by_degenerating_args (phi))
|
&& !phi_convertible_by_degenerating_args (phi))
|
||||||
{
|
any_complicated_phi = true;
|
||||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
|
||||||
fprintf (dump_file, "Phi can't be predicated by single cond.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1012,8 +1009,6 @@ has_pred_critical_p (basic_block bb)
|
||||||
- it is after the exit block but before the latch,
|
- it is after the exit block but before the latch,
|
||||||
- its edges are not normal.
|
- its edges are not normal.
|
||||||
|
|
||||||
Last restriction is valid if aggressive_if_conv is false.
|
|
||||||
|
|
||||||
EXIT_BB is the basic block containing the exit of the LOOP. BB is
|
EXIT_BB is the basic block containing the exit of the LOOP. BB is
|
||||||
inside LOOP. */
|
inside LOOP. */
|
||||||
|
|
||||||
|
|
@ -1062,19 +1057,6 @@ if_convertible_bb_p (struct loop *loop, basic_block bb, basic_block exit_bb)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At least one incoming edge has to be non-critical as otherwise edge
|
|
||||||
predicates are not equal to basic-block predicates of the edge
|
|
||||||
source. This check is skipped if aggressive_if_conv is true. */
|
|
||||||
if (!aggressive_if_conv
|
|
||||||
&& EDGE_COUNT (bb->preds) > 1
|
|
||||||
&& bb != loop->header
|
|
||||||
&& all_preds_critical_p (bb))
|
|
||||||
{
|
|
||||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
|
||||||
fprintf (dump_file, "only critical predecessors\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2380,11 +2362,16 @@ version_loop_for_if_conversion (struct loop *loop)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Performs splitting of critical edges if aggressive_if_conv is true.
|
/* Performs splitting of critical edges. Skip splitting and return false
|
||||||
Returns false if loop won't be if converted and true otherwise. */
|
if LOOP will not be converted because:
|
||||||
|
|
||||||
|
- LOOP is not well formed.
|
||||||
|
- LOOP has PHI with more than MAX_PHI_ARG_NUM arguments.
|
||||||
|
|
||||||
|
Last restriction is valid only if AGGRESSIVE_IF_CONV is false. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ifcvt_split_critical_edges (struct loop *loop)
|
ifcvt_split_critical_edges (struct loop *loop, bool aggressive_if_conv)
|
||||||
{
|
{
|
||||||
basic_block *body;
|
basic_block *body;
|
||||||
basic_block bb;
|
basic_block bb;
|
||||||
|
|
@ -2393,30 +2380,51 @@ ifcvt_split_critical_edges (struct loop *loop)
|
||||||
gimple *stmt;
|
gimple *stmt;
|
||||||
edge e;
|
edge e;
|
||||||
edge_iterator ei;
|
edge_iterator ei;
|
||||||
|
vec<edge> critical_edges = vNULL;
|
||||||
|
|
||||||
if (num <= 2)
|
/* Loop is not well formed. */
|
||||||
return false;
|
if (num <= 2 || loop->inner || !single_exit (loop))
|
||||||
if (loop->inner)
|
|
||||||
return false;
|
|
||||||
if (!single_exit (loop))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
body = get_loop_body (loop);
|
body = get_loop_body (loop);
|
||||||
for (i = 0; i < num; i++)
|
for (i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
bb = body[i];
|
bb = body[i];
|
||||||
if (bb == loop->latch
|
if (!aggressive_if_conv
|
||||||
|| bb_with_exit_edge_p (loop, bb))
|
&& phi_nodes (bb)
|
||||||
|
&& EDGE_COUNT (bb->preds) > MAX_PHI_ARG_NUM)
|
||||||
|
{
|
||||||
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||||
|
fprintf (dump_file,
|
||||||
|
"BB %d has complicated PHI with more than %u args.\n",
|
||||||
|
bb->index, MAX_PHI_ARG_NUM);
|
||||||
|
|
||||||
|
free (body);
|
||||||
|
critical_edges.release ();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (bb == loop->latch || bb_with_exit_edge_p (loop, bb))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
stmt = last_stmt (bb);
|
stmt = last_stmt (bb);
|
||||||
/* Skip basic blocks not ending with conditional branch. */
|
/* Skip basic blocks not ending with conditional branch. */
|
||||||
if (!(stmt && gimple_code (stmt) == GIMPLE_COND))
|
if (!stmt || gimple_code (stmt) != GIMPLE_COND)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||||
if (EDGE_CRITICAL_P (e) && e->dest->loop_father == loop)
|
if (EDGE_CRITICAL_P (e) && e->dest->loop_father == loop)
|
||||||
split_edge (e);
|
critical_edges.safe_push (e);
|
||||||
}
|
}
|
||||||
free (body);
|
free (body);
|
||||||
|
|
||||||
|
while (critical_edges.length () > 0)
|
||||||
|
{
|
||||||
|
e = critical_edges.pop ();
|
||||||
|
/* Don't split if bb can be predicated along non-critical edge. */
|
||||||
|
if (EDGE_COUNT (e->dest->preds) > 2 || all_preds_critical_p (e->dest))
|
||||||
|
split_edge (e);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2713,12 +2721,16 @@ static unsigned int
|
||||||
tree_if_conversion (struct loop *loop)
|
tree_if_conversion (struct loop *loop)
|
||||||
{
|
{
|
||||||
unsigned int todo = 0;
|
unsigned int todo = 0;
|
||||||
|
bool aggressive_if_conv;
|
||||||
|
|
||||||
ifc_bbs = NULL;
|
ifc_bbs = NULL;
|
||||||
any_pred_load_store = false;
|
any_pred_load_store = false;
|
||||||
|
any_complicated_phi = false;
|
||||||
|
|
||||||
/* Set up aggressive if-conversion for loops marked with simd pragma. */
|
/* Apply more aggressive if-conversion when loop or its outer loop were
|
||||||
|
marked with simd pragma. When that's the case, we try to if-convert
|
||||||
|
loop containing PHIs with more than MAX_PHI_ARG_NUM arguments. */
|
||||||
aggressive_if_conv = loop->force_vectorize;
|
aggressive_if_conv = loop->force_vectorize;
|
||||||
/* Check either outer loop was marked with simd pragma. */
|
|
||||||
if (!aggressive_if_conv)
|
if (!aggressive_if_conv)
|
||||||
{
|
{
|
||||||
struct loop *outer_loop = loop_outer (loop);
|
struct loop *outer_loop = loop_outer (loop);
|
||||||
|
|
@ -2726,20 +2738,20 @@ tree_if_conversion (struct loop *loop)
|
||||||
aggressive_if_conv = true;
|
aggressive_if_conv = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aggressive_if_conv)
|
if (!ifcvt_split_critical_edges (loop, aggressive_if_conv))
|
||||||
if (!ifcvt_split_critical_edges (loop))
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (!if_convertible_loop_p (loop)
|
if (!if_convertible_loop_p (loop)
|
||||||
|| !dbg_cnt (if_conversion_tree))
|
|| !dbg_cnt (if_conversion_tree))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (any_pred_load_store
|
if ((any_pred_load_store || any_complicated_phi)
|
||||||
&& ((!flag_tree_loop_vectorize && !loop->force_vectorize)
|
&& ((!flag_tree_loop_vectorize && !loop->force_vectorize)
|
||||||
|| loop->dont_vectorize))
|
|| loop->dont_vectorize))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (any_pred_load_store && !version_loop_for_if_conversion (loop))
|
if ((any_pred_load_store || any_complicated_phi)
|
||||||
|
&& !version_loop_for_if_conversion (loop))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Now all statements are if-convertible. Combine all the basic
|
/* Now all statements are if-convertible. Combine all the basic
|
||||||
|
|
@ -2749,11 +2761,8 @@ tree_if_conversion (struct loop *loop)
|
||||||
|
|
||||||
/* Delete dead predicate computations and repair tree correspondent
|
/* Delete dead predicate computations and repair tree correspondent
|
||||||
to bool pattern to delete multiple uses of predicates. */
|
to bool pattern to delete multiple uses of predicates. */
|
||||||
if (aggressive_if_conv)
|
|
||||||
{
|
|
||||||
ifcvt_local_dce (loop->header);
|
ifcvt_local_dce (loop->header);
|
||||||
ifcvt_repair_bool_pattern (loop->header);
|
ifcvt_repair_bool_pattern (loop->header);
|
||||||
}
|
|
||||||
|
|
||||||
todo |= TODO_cleanup_cfg;
|
todo |= TODO_cleanup_cfg;
|
||||||
mark_virtual_operands_for_renaming (cfun);
|
mark_virtual_operands_for_renaming (cfun);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue