Commit 1cfcd39e by Bin Cheng Committed by Bin Cheng

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
parent 15526589
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. ...@@ -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, ...@@ -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.",
......
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
......
/* { 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" } } */
/* { 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" } } */
...@@ -113,11 +113,22 @@ along with GCC; see the file COPYING3. If not see ...@@ -113,11 +113,22 @@ along with GCC; see the file COPYING3. If not see
#include "varasm.h" #include "varasm.h"
#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, ...@@ -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) ...@@ -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) ...@@ -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 && !phi_convertible_by_degenerating_args (phi))
&& !aggressive_if_conv any_complicated_phi = true;
&& !phi_convertible_by_degenerating_args (phi))
{
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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_repair_bool_pattern (loop->header);
ifcvt_local_dce (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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment