diff options
author | Bin Cheng <bin.cheng@arm.com> | 2016-05-03 09:04:46 +0000 |
---|---|---|
committer | Bin Cheng <amker@gcc.gnu.org> | 2016-05-03 09:04:46 +0000 |
commit | 1cfcd39eee915a7582adc113fa6e7faac8b943e4 (patch) | |
tree | 5411de44c126dfd942b7250b8f84f5f31dbfa368 | |
parent | 15526589cf190bc111e1ef27f713e2d46c449172 (diff) | |
download | gcc-1cfcd39eee915a7582adc113fa6e7faac8b943e4.zip gcc-1cfcd39eee915a7582adc113fa6e7faac8b943e4.tar.gz gcc-1cfcd39eee915a7582adc113fa6e7faac8b943e4.tar.bz2 |
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
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 4 | ||||
-rw-r--r-- | gcc/params.def | 6 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ifc-pr56541.c | 25 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/vect/pr56541.c | 27 | ||||
-rw-r--r-- | gcc/tree-if-conv.c | 131 |
7 files changed, 155 insertions, 61 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 45670bc..ffe45b7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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> * tree-ssa-loop-ivopts.c (get_computation_cost_at): Check depends_on diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 515d948..f5413fa 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -9020,6 +9020,10 @@ Large expressions slow the analyzer. Bound on the complexity of the expressions in the scalar evolutions 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 The maximum number of run-time checks that can be performed when doing loop versioning for alignment in the vectorizer. diff --git a/gcc/params.def b/gcc/params.def index 9e05401..62a1e404 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -530,6 +530,12 @@ DEFPARAM(PARAM_SCEV_MAX_EXPR_COMPLEXITY, "Bound on the complexity of the expressions in the scalar evolutions analyzer.", 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, "vect-max-version-for-alignment-checks", "Bound on number of runtime checks inserted by the vectorizer's loop versioning for alignment check.", diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0f91bdf..6ce2c7e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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> * gcc.target/powerpc/float128-complex-1.c: New tests for complex diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ifc-pr56541.c b/gcc/testsuite/gcc.dg/tree-ssa/ifc-pr56541.c new file mode 100644 index 0000000..a52baca --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ifc-pr56541.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr56541.c b/gcc/testsuite/gcc.dg/vect/pr56541.c new file mode 100644 index 0000000..16b8d7c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr56541.c @@ -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" } } */ diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 32ced164..97b62b7 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -113,11 +113,22 @@ along with GCC; see the file COPYING3. If not see #include "varasm.h" #include "builtins.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 during if conversion. */ 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 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. */ 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. */ static hash_map<innermost_loop_behavior_hash, 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 - and it belongs to basic block BB. - - PHI is not if-convertible if: - - it has more than 2 arguments. - - When the aggressive_if_conv is set, PHI can have more than - two arguments. */ + and it belongs to basic block BB. Note at this point, it is sure + that PHI is if-convertible. This function updates global variable + ANY_COMPLICATED_PHI if PHI is complicated. */ static bool 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); } - if (bb != loop->header) - { - if (gimple_phi_num_args (phi) > 2 - && !aggressive_if_conv - && !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; - } - } + if (bb != loop->header + && gimple_phi_num_args (phi) > 2 + && !phi_convertible_by_degenerating_args (phi)) + any_complicated_phi = true; return true; } @@ -1012,8 +1009,6 @@ has_pred_critical_p (basic_block bb) - it is after the exit block but before the latch, - 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 inside LOOP. */ @@ -1062,19 +1057,6 @@ if_convertible_bb_p (struct loop *loop, basic_block bb, basic_block exit_bb) 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; } @@ -2380,11 +2362,16 @@ version_loop_for_if_conversion (struct loop *loop) return true; } -/* Performs splitting of critical edges if aggressive_if_conv is true. - Returns false if loop won't be if converted and true otherwise. */ +/* Performs splitting of critical edges. Skip splitting and return false + 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 -ifcvt_split_critical_edges (struct loop *loop) +ifcvt_split_critical_edges (struct loop *loop, bool aggressive_if_conv) { basic_block *body; basic_block bb; @@ -2393,30 +2380,51 @@ ifcvt_split_critical_edges (struct loop *loop) gimple *stmt; edge e; edge_iterator ei; + vec<edge> critical_edges = vNULL; - if (num <= 2) - return false; - if (loop->inner) - return false; - if (!single_exit (loop)) + /* Loop is not well formed. */ + if (num <= 2 || loop->inner || !single_exit (loop)) return false; body = get_loop_body (loop); for (i = 0; i < num; i++) { bb = body[i]; - if (bb == loop->latch - || bb_with_exit_edge_p (loop, bb)) + if (!aggressive_if_conv + && 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; + stmt = last_stmt (bb); /* Skip basic blocks not ending with conditional branch. */ - if (!(stmt && gimple_code (stmt) == GIMPLE_COND)) + if (!stmt || gimple_code (stmt) != GIMPLE_COND) continue; + FOR_EACH_EDGE (e, ei, bb->succs) if (EDGE_CRITICAL_P (e) && e->dest->loop_father == loop) - split_edge (e); + critical_edges.safe_push (e); } 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; } @@ -2713,12 +2721,16 @@ static unsigned int tree_if_conversion (struct loop *loop) { unsigned int todo = 0; + bool aggressive_if_conv; + ifc_bbs = NULL; 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; - /* Check either outer loop was marked with simd pragma. */ if (!aggressive_if_conv) { struct loop *outer_loop = loop_outer (loop); @@ -2726,20 +2738,20 @@ tree_if_conversion (struct loop *loop) aggressive_if_conv = true; } - if (aggressive_if_conv) - if (!ifcvt_split_critical_edges (loop)) - goto cleanup; + if (!ifcvt_split_critical_edges (loop, aggressive_if_conv)) + goto cleanup; if (!if_convertible_loop_p (loop) || !dbg_cnt (if_conversion_tree)) goto cleanup; - if (any_pred_load_store + if ((any_pred_load_store || any_complicated_phi) && ((!flag_tree_loop_vectorize && !loop->force_vectorize) || loop->dont_vectorize)) 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; /* 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 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; mark_virtual_operands_for_renaming (cfun); |