From b54819879e0518b3f1acc5242f9c1d86dd1b9e3c Mon Sep 17 00:00:00 2001 From: Bin Cheng Date: Wed, 23 Nov 2016 12:44:08 +0000 Subject: [PATCH] fold-const.c (fold_cond_expr_with_comparison): Move simplification for A cmp C1 ? A : C2 to below, also simplify remaining code. * 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 * 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. From-SVN: r242750 --- gcc/ChangeLog | 9 +++ gcc/fold-const.c | 95 +++-------------------- gcc/match.pd | 61 +++++++++++++++ gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/gcc.dg/fold-cond_expr-1.c | 47 +++++++++++ gcc/testsuite/gcc.dg/fold-condcmpconv-1.c | 14 ++++ gcc/testsuite/gcc.dg/fold-condcmpconv-2.c | 15 ++++ gcc/testsuite/gcc.dg/tree-ssa/pr66726.c | 9 ++- gcc/tree-if-conv.c | 10 +++ 9 files changed, 176 insertions(+), 90 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/fold-cond_expr-1.c create mode 100644 gcc/testsuite/gcc.dg/fold-condcmpconv-1.c create mode 100644 gcc/testsuite/gcc.dg/fold-condcmpconv-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0bafde2dba6..a330d7a51a4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2016-11-23 Bin Cheng + + * 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 Martin Jambor diff --git a/gcc/fold-const.c b/gcc/fold-const.c index a0055c45c37..cbfbc24222c 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 6665412a4af..2599d27c528 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 64fbed77e89..604c5918c3b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-11-23 Bin Cheng + + * 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 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 00000000000..68ec75480ad --- /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 00000000000..321294f4b96 --- /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 00000000000..5d3ef4a1e60 --- /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 a4c74182059..e66d383c55b 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 13e12c63e1e..5716deb7974 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -1749,6 +1749,14 @@ gen_phi_arg_condition (gphi *phi, vec *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)) -- 2.30.2