aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/fold-const.c95
-rw-r--r--gcc/match.pd61
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/fold-cond_expr-1.c47
-rw-r--r--gcc/testsuite/gcc.dg/fold-condcmpconv-1.c14
-rw-r--r--gcc/testsuite/gcc.dg/fold-condcmpconv-2.c15
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr66726.c9
-rw-r--r--gcc/tree-if-conv.c10
9 files changed, 176 insertions, 90 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0bafde2..a330d7a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2016-11-23 Bin Cheng <bin.cheng@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.
+
2016-11-23 Martin Liska <mliska@suse.cz>
Martin Jambor <mjambor@suse.cz>
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index a0055c4..cbfbc24 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 6665412..2599d27 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1953,6 +1953,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/ChangeLog b/gcc/testsuite/ChangeLog
index 64fbed7..604c591 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2016-11-23 Bin Cheng <bin.cheng@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.
+
2016-11-23 Richard Biener <rguenther@suse.de>
PR middle-end/71762
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 13e12c6..5716deb 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))