Hi,
This is a rework of https://gcc.gnu.org/ml/gcc-patches/2016-10/msg02005.html.  
According to review comment, I extended the original patch and made it covering 
last kind simplification of fold_cond_expr_with_comparison (Well, this patch 
handles <, <=, > and >=.  == will be handled by a follow up).  This patch also 
adds several tests, some tests are for existing fold_cond_expr_with_comparison 
simplification but not covered yet; others are for new extension.
Bootstrap and test on x86_64 and AArch64 along with following patches, is it OK?

Thanks,
bin

2016-11-16  Bin Cheng  <bin.ch...@arm.com>

        * fold-const.c (fold_cond_expr_with_comparison): Move simplification
        for A cmp C1 ? A : C2 to below, also simplify remaining code.
        * match.pd: Move and extend simplification from above to here:
        (cond (cmp (convert1? x) c1) (convert2? x) c2) -> (minmax (x c)).
        * tree-if-conv.c (ifcvt_follow_ssa_use_edges): New func.
        (predicate_scalar_phi): Call fold_stmt using the new valueize func.

gcc/testsuite/ChangeLog
2016-11-16  Bin Cheng  <bin.ch...@arm.com>

        * gcc.dg/fold-cond_expr-1.c: New test.
        * gcc.dg/fold-condcmpconv-1.c: New test.
        * gcc.dg/fold-condcmpconv-2.c: New test.
        * gcc.dg/tree-ssa/pr66726.c: Adjust test strings.
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index c597414..1e61ccf 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -5210,95 +5210,18 @@ fold_cond_expr_with_comparison (location_t loc, tree 
type,
        }
     }
 
-  /* If this is A op C1 ? A : C2 with C1 and C2 constant integers,
-     we might still be able to simplify this.  For example,
-     if C1 is one less or one more than C2, this might have started
-     out as a MIN or MAX and been transformed by this function.
-     Only good for INTEGER_TYPEs, because we need TYPE_MAX_VALUE.  */
+  /* If this is A == C1 ? A : C2 with C1 and C2 constant integers,
+     we simplify it into A == C1 ? C1 : C2.  */
 
-  if (INTEGRAL_TYPE_P (type)
+  if (comp_code == EQ_EXPR
+      && INTEGRAL_TYPE_P (type)
       && TREE_CODE (arg01) == INTEGER_CST
+      && TREE_CODE (arg1) != INTEGER_CST
       && TREE_CODE (arg2) == INTEGER_CST)
-    switch (comp_code)
-      {
-      case EQ_EXPR:
-       if (TREE_CODE (arg1) == INTEGER_CST)
-         break;
-       /* We can replace A with C1 in this case.  */
-       arg1 = fold_convert_loc (loc, type, arg01);
-       return fold_build3_loc (loc, COND_EXPR, type, arg0, arg1, arg2);
-
-      case LT_EXPR:
-       /* If C1 is C2 + 1, this is min(A, C2), but use ARG00's type for
-          MIN_EXPR, to preserve the signedness of the comparison.  */
-       if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
-                              OEP_ONLY_CONST)
-           && operand_equal_p (arg01,
-                               const_binop (PLUS_EXPR, arg2,
-                                            build_int_cst (type, 1)),
-                               OEP_ONLY_CONST))
-         {
-           tem = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (arg00), arg00,
-                                  fold_convert_loc (loc, TREE_TYPE (arg00),
-                                                    arg2));
-           return fold_convert_loc (loc, type, tem);
-         }
-       break;
-
-      case LE_EXPR:
-       /* If C1 is C2 - 1, this is min(A, C2), with the same care
-          as above.  */
-       if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
-                              OEP_ONLY_CONST)
-           && operand_equal_p (arg01,
-                               const_binop (MINUS_EXPR, arg2,
-                                            build_int_cst (type, 1)),
-                               OEP_ONLY_CONST))
-         {
-           tem = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (arg00), arg00,
-                                  fold_convert_loc (loc, TREE_TYPE (arg00),
-                                                    arg2));
-           return fold_convert_loc (loc, type, tem);
-         }
-       break;
-
-      case GT_EXPR:
-       /* If C1 is C2 - 1, this is max(A, C2), but use ARG00's type for
-          MAX_EXPR, to preserve the signedness of the comparison.  */
-       if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
-                              OEP_ONLY_CONST)
-           && operand_equal_p (arg01,
-                               const_binop (MINUS_EXPR, arg2,
-                                            build_int_cst (type, 1)),
-                               OEP_ONLY_CONST))
-         {
-           tem = fold_build2_loc (loc, MAX_EXPR, TREE_TYPE (arg00), arg00,
-                                  fold_convert_loc (loc, TREE_TYPE (arg00),
-                                                    arg2));
-           return fold_convert_loc (loc, type, tem);
-         }
-       break;
-
-      case GE_EXPR:
-       /* If C1 is C2 + 1, this is max(A, C2), with the same care as above.  */
-       if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
-                              OEP_ONLY_CONST)
-           && operand_equal_p (arg01,
-                               const_binop (PLUS_EXPR, arg2,
-                                            build_int_cst (type, 1)),
-                               OEP_ONLY_CONST))
-         {
-           tem = fold_build2_loc (loc, MAX_EXPR, TREE_TYPE (arg00), arg00,
-                                  fold_convert_loc (loc, TREE_TYPE (arg00),
-                                                    arg2));
-           return fold_convert_loc (loc, type, tem);
-         }
-       break;
-      case NE_EXPR:
-       break;
-      default:
-       gcc_unreachable ();
-      }
+    {
+      arg1 = fold_convert_loc (loc, type, arg01);
+      return fold_build3_loc (loc, COND_EXPR, type, arg0, arg1, arg2);
+    }
 
   return NULL_TREE;
 }
diff --git a/gcc/match.pd b/gcc/match.pd
index 79a418f..4beac4e 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1937,6 +1937,67 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (if (integer_zerop (@0))
    @2)))
 
+/* Simplification moved from fold_cond_expr_with_comparison.  It may also
+   be extended.  */
+/* (cond (cmp (convert1? x) c1) (convert2? x) c2) -> (minmax (x c)) if:
+     1) Conversions are type widening from smaller type.
+     2) Const c1 equals to c2 after canonicalizing comparison.
+     3) Comparison has tree code LT, LE, GT or GE.
+   This specific pattern is needed when (cmp (convert x) c) may not
+   be simplified by comparison patterns because of multiple uses of
+   x.  It also makes sense here because simplifying across multiple
+   referred var is always benefitial for complicated cases.  */
+(for cmp (lt le gt ge)
+ (simplify
+  (cond (cmp@0 (convert1? @1) INTEGER_CST@3) (convert2? @1) INTEGER_CST@2)
+  (with
+   {
+     tree from_type = TREE_TYPE (@1);
+     tree c1_type = TREE_TYPE (@3), c2_type = TREE_TYPE (@2);
+     enum tree_code code = TREE_CODE (@0), cmp_code = TREE_CODE (@0);
+
+     if (int_fits_type_p (@2, from_type)
+        && (types_match (c1_type, from_type)
+            || (TYPE_PRECISION (c1_type) > TYPE_PRECISION (from_type)
+                && (TYPE_UNSIGNED (from_type)
+                    || TYPE_SIGN (c1_type) == TYPE_SIGN (from_type))))
+        && (types_match (c2_type, from_type)
+            || (TYPE_PRECISION (c2_type) > TYPE_PRECISION (from_type)
+                && (TYPE_UNSIGNED (from_type)
+                    || TYPE_SIGN (c2_type) == TYPE_SIGN (from_type)))))
+       {
+        if (wi::to_widest (@3) == (wi::to_widest (@2) - 1))
+          {
+            /* X <= Y - 1 equals to X < Y.  */
+            if (cmp_code == LE_EXPR)
+              code = LT_EXPR;
+            /* X > Y - 1 equals to X >= Y.  */
+            if (cmp_code == GT_EXPR)
+              code = GE_EXPR;
+          }
+        if (wi::to_widest (@3) == (wi::to_widest (@2) + 1))
+          {
+            /* X < Y + 1 equals to X <= Y.  */
+            if (cmp_code == LT_EXPR)
+              code = LE_EXPR;
+            /* X >= Y + 1 equals to X > Y.  */
+            if (cmp_code == GE_EXPR)
+              code = GT_EXPR;
+          }
+        if (code != cmp_code || wi::to_widest (@2) == wi::to_widest (@3))
+          {
+            if (cmp_code == LT_EXPR || cmp_code == LE_EXPR)
+              code = MIN_EXPR;
+            if (cmp_code == GT_EXPR || cmp_code == GE_EXPR)
+              code = MAX_EXPR;
+          }
+       }
+   }
+   (if (code == MAX_EXPR)
+    (convert (max @1 (convert:from_type @2)))
+    (if (code == MIN_EXPR)
+     (convert (min @1 (convert:from_type @2))))))))
+
 (for cnd (cond vec_cond)
  /* A ? B : (A ? X : C) -> A ? B : C.  */
  (simplify
diff --git a/gcc/testsuite/gcc.dg/fold-cond_expr-1.c 
b/gcc/testsuite/gcc.dg/fold-cond_expr-1.c
new file mode 100644
index 0000000..68ec754
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-cond_expr-1.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+min1 (signed char op1, signed char op2)
+{
+  return (op1 < 25) ? (int)op1 : 24;
+}
+int
+min2 (signed char op1, signed char op2)
+{
+  return (op1 <= 24) ? (int)op1 : 25;
+}
+int
+min3 (unsigned char op1, unsigned char op2)
+{
+  return (op1 < 25) ? (unsigned int)op1 : 24;
+}
+int
+min4 (unsigned char op1, unsigned char op2)
+{
+  return (op1 <= 24) ? (unsigned int)op1 : 25;
+}
+int
+max1 (signed char op1, signed char op2)
+{
+  return (op1 > 24) ? (int)op1 : 25;
+}
+int
+max2 (signed char op1, signed char op2)
+{
+  return (op1 >= 25) ? (int)op1 : 24;
+}
+int
+max3 (unsigned char op1, unsigned char op2)
+{
+  return (op1 > 24) ? (unsigned int)op1 : 25;
+}
+int
+max4 (unsigned char op1, unsigned char op2)
+{
+  return (op1 >= 25) ? (unsigned int)op1 : 24;
+}
+
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR" 4 "optimized" } } */
+
diff --git a/gcc/testsuite/gcc.dg/fold-condcmpconv-1.c 
b/gcc/testsuite/gcc.dg/fold-condcmpconv-1.c
new file mode 100644
index 0000000..321294f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-condcmpconv-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-tree-ifcvt" } */
+
+int foo (unsigned short a[], unsigned int x)
+{
+  unsigned int i;
+  for (i = 0; i < 1000; i++)
+    {
+      x = a[i];
+      a[i] = (unsigned short)(x >= 255 ? 255 : x);
+    }  return x;
+}
+
+/* { dg-final { scan-tree-dump " = MIN_EXPR <" "ifcvt" } } */
diff --git a/gcc/testsuite/gcc.dg/fold-condcmpconv-2.c 
b/gcc/testsuite/gcc.dg/fold-condcmpconv-2.c
new file mode 100644
index 0000000..5d3ef4a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fold-condcmpconv-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-tree-ifcvt" } */
+
+int foo (short a[], int x)
+{
+  unsigned int i;
+  for (i = 0; i < 1000; i++)
+    {
+      x = a[i];
+      a[i] = (short)(x <= 0 ? 0 : x);
+    }  return x;
+}
+
+
+/* { dg-final { scan-tree-dump " = MAX_EXPR <" "ifcvt" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c
index a4c7418..e66d383 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c
@@ -1,6 +1,5 @@
-
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-phiopt1-details" } */
+/* { dg-options "-O2 -fdump-tree-gimple" } */
 
 extern unsigned short mode_size[];
 
@@ -10,6 +9,8 @@ oof (int mode)
   return (64 < mode_size[mode] ? 64 : mode_size[mode]);
 }
 
-/* { dg-final { scan-tree-dump-times "factor conversion out" 1 "phiopt1" } } */
-/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */
+/* With simplifications transforming cond_expr int min/max_expr
+   supported by match.pd patterns, we can optimize this at early
+   stage of compilation, rather than relying on phiopt for that.  */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "gimple" } } */
 
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 0a20189..24cca2e 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -1749,6 +1749,14 @@ gen_phi_arg_condition (gphi *phi, vec<int> *occur,
   return cond;
 }
 
+/* Local valueization callback that follows all-use SSA edges.  */
+
+static tree
+ifcvt_follow_ssa_use_edges (tree val)
+{
+  return val;
+}
+
 /* Replace a scalar PHI node with a COND_EXPR using COND as condition.
    This routine can handle PHI nodes with more than two arguments.
 
@@ -1844,6 +1852,8 @@ predicate_scalar_phi (gphi *phi, gimple_stmt_iterator 
*gsi)
                                    arg0, arg1);
       new_stmt = gimple_build_assign (res, rhs);
       gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+      gimple_stmt_iterator new_gsi = gsi_for_stmt (new_stmt);
+      fold_stmt (&new_gsi, ifcvt_follow_ssa_use_edges);
       update_stmt (new_stmt);
 
       if (dump_file && (dump_flags & TDF_DETAILS))

Reply via email to