Hi, The second issue revealed by PR69489 is tree ifcvt could not convert PHI nodes with more than 2 arguments. Among these nodes, there is a special kind of PHI which can be handled. Precisely, if the PHI node satisfies below two conditions: 1) Number of PHI arguments with different values equals to 2 and one argument has the only occurrence. 2) The edge corresponding to the unique argument isn't critical edge.
Such PHI can be degenerated and handled just like PHI node with only two arguments. For example: res = PHI <A_1(e1), A_1(e2), A_2(e3), A_1(e4)>; can be transformed into: res = (predicate of e3) ? A_2 : A_1; This patch fixes the issue. I know we may be able to further relax the check and allow handling of general multiple args PHI node, this can be a starter since the change is kind of trivial. Bootstrap & test on x86_64 & AArch64. Though the first part patch at https://gcc.gnu.org/ml/gcc-patches/2016-03/msg00888.html needs to be revised, this one is quite independent apart from the test case itself. So any opinions? Thanks, bin 2016-03-21 Bin Cheng <bin.ch...@arm.com> PR tree-optimization/69489 * tree-if-conv.c (phi_convertible_by_degenerating_args): New. (if_convertible_phi_p): Call phi_convertible_by_degenerating_args. Revise dump message. (if_convertible_bb_p): Remove check on edge count of basic block's predecessors. gcc/testsuite/ChangeLog 2016-03-21 Bin Cheng <bin.ch...@arm.com> PR tree-optimization/69489 * gcc.dg/tree-ssa/ifc-pr69489-2.c: New test.
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 9e305c7..7bac883 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -513,6 +513,65 @@ bb_with_exit_edge_p (struct loop *loop, basic_block bb) return false; } +/* Given PHI which has more than two arguments, this function checks if + it's if-convertible by degenerating its arguments. Specifically, if + below two conditions are satisfied: + + 1) Number of PHI arguments with different values equals to 2 and one + argument has the only occurrence. + 2) The edge corresponding to the unique argument isn't critical edge. + + Such PHI can be handled as PHIs have only two arguments. For example, + below PHI: + + res = PHI <A_1(e1), A_1(e2), A_2(e3)>; + + can be transformed into: + + res = (predicate of e3) ? A_2 : A_1; + + Return TRUE if it is the case, FALSE otherwise. */ + +static bool +phi_convertible_by_degenerating_args (gphi *phi) +{ + edge e; + tree arg, t1 = NULL, t2 = NULL; + unsigned int i, i1, i2, n1 = 0, n2 = 0; + unsigned int num_args = gimple_phi_num_args (phi); + + gcc_assert (num_args > 2); + + for (i = 0; i < num_args; i++) + { + arg = gimple_phi_arg_def (phi, i); + if (t1 == NULL || operand_equal_p (t1, arg, 0)) + { + n1++; + i1 = i; + t1 = arg; + } + else if (t2 == NULL || operand_equal_p (t2, arg, 0)) + { + n2++; + i2 = i; + t2 = arg; + } + else + return false; + } + + if (n1 != 1 && n2 != 1) + return false; + + /* Check if the edge corresponding to the unique arg is critical. */ + e = gimple_phi_arg_edge (phi, (n1 == 1) ? i1 : i2); + if (EDGE_COUNT (e->src->succs) > 1) + return false; + + return true; +} + /* Return true when PHI is if-convertible. PHI is part of loop LOOP and it belongs to basic block BB. @@ -539,10 +598,11 @@ if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi, if (bb != loop->header) { if (gimple_phi_num_args (phi) != 2 - && !aggressive_if_conv) + && !aggressive_if_conv + && !phi_convertible_by_degenerating_args (phi)) { if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "More than two phi node args.\n"); + fprintf (dump_file, "Phi can't be predicated by single cond.\n"); return false; } } @@ -949,10 +1009,6 @@ if_convertible_bb_p (struct loop *loop, basic_block bb, basic_block exit_bb) if (EDGE_COUNT (bb->succs) > 2) return false; - if (EDGE_COUNT (bb->preds) > 2 - && !aggressive_if_conv) - return false; - if (exit_bb) { if (bb != loop->latch) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ifc-pr69489-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ifc-pr69489-2.c new file mode 100644 index 0000000..d427600 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ifc-pr69489-2.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-S -O2 -ftree-vectorize -fdump-tree-ifcvt-stats" { target *-*-* } } */ + +double +foo (const char *u, const char *v, long n) +{ + long i, n1 = 0, n2 = 0; + + for (i = 0; i < n; i++) + { + n2 += (u[i] && !v[i]); + n1 += (!u[i] && v[i]); + } + return (2.0 * n2 * n1); +} + +/* { dg-final { scan-tree-dump-times "Applying if-conversion" 1 "ifcvt" } } */