Message ID | alpine.DEB.2.02.1606120942100.10416@laptop-mg.saclay.inria.fr |
---|---|
State | New |
Headers | show |
On Sun, Jun 12, 2016 at 10:30 AM, Marc Glisse <marc.glisse@inria.fr> wrote: > Hello, > > this move is pretty straightforward. The transformation would probably work > just fine for any type (floats, vectors), but I didn't want the headache of > checking the behavior for NaN. > > Bootstrap+regtest on powerpc64le-unknown-linux-gnu. Ok. Thanks, Richard. > 2016-06-13 Marc Glisse <marc.glisse@inria.fr> > > * fold-const.c (optimize_minmax_comparison): Remove. > (fold_comparison): Remove call to the above. > * match.pd (MIN (X, Y) == X, MIN (X, 5) == 0, MIN (X, C1) < C2): > New transformations. > > -- > Marc Glisse > Index: gcc/fold-const.c > =================================================================== > --- gcc/fold-const.c (revision 237336) > +++ gcc/fold-const.c (working copy) > @@ -121,22 +121,20 @@ static tree eval_subst (location_t, tree > static tree optimize_bit_field_compare (location_t, enum tree_code, > tree, tree, tree); > static int simple_operand_p (const_tree); > static bool simple_operand_p_2 (tree); > static tree range_binop (enum tree_code, tree, tree, int, tree, int); > static tree range_predecessor (tree); > static tree range_successor (tree); > static tree fold_range_test (location_t, enum tree_code, tree, tree, tree); > static tree fold_cond_expr_with_comparison (location_t, tree, tree, tree, > tree); > static tree unextend (tree, int, int, tree); > -static tree optimize_minmax_comparison (location_t, enum tree_code, > - tree, tree, tree); > static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *); > static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *); > static tree fold_binary_op_with_conditional_arg (location_t, > enum tree_code, tree, > tree, tree, > tree, tree, int); > static tree fold_div_compare (location_t, enum tree_code, tree, tree, > tree); > static bool reorder_operands_p (const_tree, const_tree); > static tree fold_negate_const (tree, tree); > static tree fold_not_const (const_tree, tree); > @@ -5972,124 +5970,20 @@ fold_truth_andor_1 (location_t loc, enum > ll_unsignedp || rl_unsignedp, ll_reversep); > > ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask); > if (! all_ones_mask_p (ll_mask, lnbitsize)) > result = build2_loc (loc, BIT_AND_EXPR, lntype, result, ll_mask); > > return build2_loc (loc, wanted_code, truth_type, result, > const_binop (BIT_IOR_EXPR, l_const, r_const)); > } > > -/* Optimize T, which is a comparison of a MIN_EXPR or MAX_EXPR with a > - constant. */ > - > -static tree > -optimize_minmax_comparison (location_t loc, enum tree_code code, tree type, > - tree op0, tree op1) > -{ > - tree arg0 = op0; > - enum tree_code op_code; > - tree comp_const; > - tree minmax_const; > - int consts_equal, consts_lt; > - tree inner; > - > - STRIP_SIGN_NOPS (arg0); > - > - op_code = TREE_CODE (arg0); > - minmax_const = TREE_OPERAND (arg0, 1); > - comp_const = fold_convert_loc (loc, TREE_TYPE (arg0), op1); > - consts_equal = tree_int_cst_equal (minmax_const, comp_const); > - consts_lt = tree_int_cst_lt (minmax_const, comp_const); > - inner = TREE_OPERAND (arg0, 0); > - > - /* If something does not permit us to optimize, return the original tree. > */ > - if ((op_code != MIN_EXPR && op_code != MAX_EXPR) > - || TREE_CODE (comp_const) != INTEGER_CST > - || TREE_OVERFLOW (comp_const) > - || TREE_CODE (minmax_const) != INTEGER_CST > - || TREE_OVERFLOW (minmax_const)) > - return NULL_TREE; > - > - /* Now handle all the various comparison codes. We only handle EQ_EXPR > - and GT_EXPR, doing the rest with recursive calls using logical > - simplifications. */ > - switch (code) > - { > - case NE_EXPR: case LT_EXPR: case LE_EXPR: > - { > - tree tem > - = optimize_minmax_comparison (loc, > - invert_tree_comparison (code, > false), > - type, op0, op1); > - if (tem) > - return invert_truthvalue_loc (loc, tem); > - return NULL_TREE; > - } > - > - case GE_EXPR: > - return > - fold_build2_loc (loc, TRUTH_ORIF_EXPR, type, > - optimize_minmax_comparison > - (loc, EQ_EXPR, type, arg0, comp_const), > - optimize_minmax_comparison > - (loc, GT_EXPR, type, arg0, comp_const)); > - > - case EQ_EXPR: > - if (op_code == MAX_EXPR && consts_equal) > - /* MAX (X, 0) == 0 -> X <= 0 */ > - return fold_build2_loc (loc, LE_EXPR, type, inner, comp_const); > - > - else if (op_code == MAX_EXPR && consts_lt) > - /* MAX (X, 0) == 5 -> X == 5 */ > - return fold_build2_loc (loc, EQ_EXPR, type, inner, comp_const); > - > - else if (op_code == MAX_EXPR) > - /* MAX (X, 0) == -1 -> false */ > - return omit_one_operand_loc (loc, type, integer_zero_node, inner); > - > - else if (consts_equal) > - /* MIN (X, 0) == 0 -> X >= 0 */ > - return fold_build2_loc (loc, GE_EXPR, type, inner, comp_const); > - > - else if (consts_lt) > - /* MIN (X, 0) == 5 -> false */ > - return omit_one_operand_loc (loc, type, integer_zero_node, inner); > - > - else > - /* MIN (X, 0) == -1 -> X == -1 */ > - return fold_build2_loc (loc, EQ_EXPR, type, inner, comp_const); > - > - case GT_EXPR: > - if (op_code == MAX_EXPR && (consts_equal || consts_lt)) > - /* MAX (X, 0) > 0 -> X > 0 > - MAX (X, 0) > 5 -> X > 5 */ > - return fold_build2_loc (loc, GT_EXPR, type, inner, comp_const); > - > - else if (op_code == MAX_EXPR) > - /* MAX (X, 0) > -1 -> true */ > - return omit_one_operand_loc (loc, type, integer_one_node, inner); > - > - else if (op_code == MIN_EXPR && (consts_equal || consts_lt)) > - /* MIN (X, 0) > 0 -> false > - MIN (X, 0) > 5 -> false */ > - return omit_one_operand_loc (loc, type, integer_zero_node, inner); > - > - else > - /* MIN (X, 0) > -1 -> X > -1 */ > - return fold_build2_loc (loc, GT_EXPR, type, inner, comp_const); > - > - default: > - return NULL_TREE; > - } > -} > - > /* T is an integer expression that is being multiplied, divided, or taken a > modulus (CODE says which and what kind of divide or modulus) by a > constant C. See if we can eliminate that operation by folding it with > other operations already in T. WIDE_TYPE, if non-null, is a type that > should be used for the computation if wider than our type. > > For example, if we are dividing (X * 8) + (Y * 16) by 4, we can return > (X * 2) + (Y * 4). We must, however, be assured that either the > original > expression would not overflow or that overflow is undefined for the type > in the language in question. > @@ -8712,32 +8606,20 @@ fold_comparison (location_t loc, enum tr > TREE_TYPE (arg0), > variable1, cst), > variable2); > } > } > > tem = maybe_canonicalize_comparison (loc, code, type, arg0, arg1); > if (tem) > return tem; > > - /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a > - constant, we can simplify it. */ > - if (TREE_CODE (arg1) == INTEGER_CST > - && (TREE_CODE (arg0) == MIN_EXPR > - || TREE_CODE (arg0) == MAX_EXPR) > - && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) > - { > - tem = optimize_minmax_comparison (loc, code, type, op0, op1); > - if (tem) > - return tem; > - } > - > /* If we are comparing an expression that just has comparisons > of two integer values, arithmetic expressions of those comparisons, > and constants, we can simplify it. There are only three cases > to check: the two values can either be equal, the first can be > greater, or the second can be greater. Fold the expression for > those three values. Since each value must be 0 or 1, we have > eight possibilities, each of which corresponds to the constant 0 > or 1 or one of the six possible comparisons. > > This handles common cases like (a > b) == 0 but also handles > Index: gcc/match.pd > =================================================================== > --- gcc/match.pd (revision 237336) > +++ gcc/match.pd (working copy) > @@ -1305,20 +1305,52 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))) > (negate (maxmin @0 @1))))) > /* MIN (~X, ~Y) -> ~MAX (X, Y) > MAX (~X, ~Y) -> ~MIN (X, Y) */ > (for minmax (min max) > maxmin (max min) > (simplify > (minmax (bit_not:s@2 @0) (bit_not:s@3 @1)) > (bit_not (maxmin @0 @1)))) > > +/* MIN (X, Y) == X -> X <= Y */ > +(for minmax (min min max max) > + cmp (eq ne eq ne ) > + out (le gt ge lt ) > + (simplify > + (cmp:c (minmax:c @0 @1) @0) > + (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))) > + (out @0 @1)))) > +/* MIN (X, 5) == 0 -> X == 0 > + MIN (X, 5) == 7 -> false */ > +(for cmp (eq ne) > + (simplify > + (cmp (min @0 INTEGER_CST@1) INTEGER_CST@2) > + (if (wi::lt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0)))) > + { constant_boolean_node (cmp == NE_EXPR, type); } > + (if (wi::gt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0)))) > + (cmp @0 @2))))) > +(for cmp (eq ne) > + (simplify > + (cmp (max @0 INTEGER_CST@1) INTEGER_CST@2) > + (if (wi::gt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0)))) > + { constant_boolean_node (cmp == NE_EXPR, type); } > + (if (wi::lt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0)))) > + (cmp @0 @2))))) > +/* MIN (X, C1) < C2 -> X < C2 || C1 < C2 */ > +(for minmax (min min max max min min max max > ) > + cmp (lt le gt ge gt ge lt le > ) > + comb (bit_ior bit_ior bit_ior bit_ior bit_and bit_and bit_and > bit_and) > + (simplify > + (cmp (minmax @0 INTEGER_CST@1) INTEGER_CST@2) > + (comb (cmp @0 @2) (cmp @1 @2)))) > + > /* Simplifications of shift and rotates. */ > > (for rotate (lrotate rrotate) > (simplify > (rotate integer_all_onesp@0 @1) > @0)) > > /* Optimize -1 >> x for arithmetic right shifts. */ > (simplify > (rshift integer_all_onesp@0 @1) >
Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 237336) +++ gcc/fold-const.c (working copy) @@ -121,22 +121,20 @@ static tree eval_subst (location_t, tree static tree optimize_bit_field_compare (location_t, enum tree_code, tree, tree, tree); static int simple_operand_p (const_tree); static bool simple_operand_p_2 (tree); static tree range_binop (enum tree_code, tree, tree, int, tree, int); static tree range_predecessor (tree); static tree range_successor (tree); static tree fold_range_test (location_t, enum tree_code, tree, tree, tree); static tree fold_cond_expr_with_comparison (location_t, tree, tree, tree, tree); static tree unextend (tree, int, int, tree); -static tree optimize_minmax_comparison (location_t, enum tree_code, - tree, tree, tree); static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *); static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *); static tree fold_binary_op_with_conditional_arg (location_t, enum tree_code, tree, tree, tree, tree, tree, int); static tree fold_div_compare (location_t, enum tree_code, tree, tree, tree); static bool reorder_operands_p (const_tree, const_tree); static tree fold_negate_const (tree, tree); static tree fold_not_const (const_tree, tree); @@ -5972,124 +5970,20 @@ fold_truth_andor_1 (location_t loc, enum ll_unsignedp || rl_unsignedp, ll_reversep); ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask); if (! all_ones_mask_p (ll_mask, lnbitsize)) result = build2_loc (loc, BIT_AND_EXPR, lntype, result, ll_mask); return build2_loc (loc, wanted_code, truth_type, result, const_binop (BIT_IOR_EXPR, l_const, r_const)); } -/* Optimize T, which is a comparison of a MIN_EXPR or MAX_EXPR with a - constant. */ - -static tree -optimize_minmax_comparison (location_t loc, enum tree_code code, tree type, - tree op0, tree op1) -{ - tree arg0 = op0; - enum tree_code op_code; - tree comp_const; - tree minmax_const; - int consts_equal, consts_lt; - tree inner; - - STRIP_SIGN_NOPS (arg0); - - op_code = TREE_CODE (arg0); - minmax_const = TREE_OPERAND (arg0, 1); - comp_const = fold_convert_loc (loc, TREE_TYPE (arg0), op1); - consts_equal = tree_int_cst_equal (minmax_const, comp_const); - consts_lt = tree_int_cst_lt (minmax_const, comp_const); - inner = TREE_OPERAND (arg0, 0); - - /* If something does not permit us to optimize, return the original tree. */ - if ((op_code != MIN_EXPR && op_code != MAX_EXPR) - || TREE_CODE (comp_const) != INTEGER_CST - || TREE_OVERFLOW (comp_const) - || TREE_CODE (minmax_const) != INTEGER_CST - || TREE_OVERFLOW (minmax_const)) - return NULL_TREE; - - /* Now handle all the various comparison codes. We only handle EQ_EXPR - and GT_EXPR, doing the rest with recursive calls using logical - simplifications. */ - switch (code) - { - case NE_EXPR: case LT_EXPR: case LE_EXPR: - { - tree tem - = optimize_minmax_comparison (loc, - invert_tree_comparison (code, false), - type, op0, op1); - if (tem) - return invert_truthvalue_loc (loc, tem); - return NULL_TREE; - } - - case GE_EXPR: - return - fold_build2_loc (loc, TRUTH_ORIF_EXPR, type, - optimize_minmax_comparison - (loc, EQ_EXPR, type, arg0, comp_const), - optimize_minmax_comparison - (loc, GT_EXPR, type, arg0, comp_const)); - - case EQ_EXPR: - if (op_code == MAX_EXPR && consts_equal) - /* MAX (X, 0) == 0 -> X <= 0 */ - return fold_build2_loc (loc, LE_EXPR, type, inner, comp_const); - - else if (op_code == MAX_EXPR && consts_lt) - /* MAX (X, 0) == 5 -> X == 5 */ - return fold_build2_loc (loc, EQ_EXPR, type, inner, comp_const); - - else if (op_code == MAX_EXPR) - /* MAX (X, 0) == -1 -> false */ - return omit_one_operand_loc (loc, type, integer_zero_node, inner); - - else if (consts_equal) - /* MIN (X, 0) == 0 -> X >= 0 */ - return fold_build2_loc (loc, GE_EXPR, type, inner, comp_const); - - else if (consts_lt) - /* MIN (X, 0) == 5 -> false */ - return omit_one_operand_loc (loc, type, integer_zero_node, inner); - - else - /* MIN (X, 0) == -1 -> X == -1 */ - return fold_build2_loc (loc, EQ_EXPR, type, inner, comp_const); - - case GT_EXPR: - if (op_code == MAX_EXPR && (consts_equal || consts_lt)) - /* MAX (X, 0) > 0 -> X > 0 - MAX (X, 0) > 5 -> X > 5 */ - return fold_build2_loc (loc, GT_EXPR, type, inner, comp_const); - - else if (op_code == MAX_EXPR) - /* MAX (X, 0) > -1 -> true */ - return omit_one_operand_loc (loc, type, integer_one_node, inner); - - else if (op_code == MIN_EXPR && (consts_equal || consts_lt)) - /* MIN (X, 0) > 0 -> false - MIN (X, 0) > 5 -> false */ - return omit_one_operand_loc (loc, type, integer_zero_node, inner); - - else - /* MIN (X, 0) > -1 -> X > -1 */ - return fold_build2_loc (loc, GT_EXPR, type, inner, comp_const); - - default: - return NULL_TREE; - } -} - /* T is an integer expression that is being multiplied, divided, or taken a modulus (CODE says which and what kind of divide or modulus) by a constant C. See if we can eliminate that operation by folding it with other operations already in T. WIDE_TYPE, if non-null, is a type that should be used for the computation if wider than our type. For example, if we are dividing (X * 8) + (Y * 16) by 4, we can return (X * 2) + (Y * 4). We must, however, be assured that either the original expression would not overflow or that overflow is undefined for the type in the language in question. @@ -8712,32 +8606,20 @@ fold_comparison (location_t loc, enum tr TREE_TYPE (arg0), variable1, cst), variable2); } } tem = maybe_canonicalize_comparison (loc, code, type, arg0, arg1); if (tem) return tem; - /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a - constant, we can simplify it. */ - if (TREE_CODE (arg1) == INTEGER_CST - && (TREE_CODE (arg0) == MIN_EXPR - || TREE_CODE (arg0) == MAX_EXPR) - && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) - { - tem = optimize_minmax_comparison (loc, code, type, op0, op1); - if (tem) - return tem; - } - /* If we are comparing an expression that just has comparisons of two integer values, arithmetic expressions of those comparisons, and constants, we can simplify it. There are only three cases to check: the two values can either be equal, the first can be greater, or the second can be greater. Fold the expression for those three values. Since each value must be 0 or 1, we have eight possibilities, each of which corresponds to the constant 0 or 1 or one of the six possible comparisons. This handles common cases like (a > b) == 0 but also handles Index: gcc/match.pd =================================================================== --- gcc/match.pd (revision 237336) +++ gcc/match.pd (working copy) @@ -1305,20 +1305,52 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))) (negate (maxmin @0 @1))))) /* MIN (~X, ~Y) -> ~MAX (X, Y) MAX (~X, ~Y) -> ~MIN (X, Y) */ (for minmax (min max) maxmin (max min) (simplify (minmax (bit_not:s@2 @0) (bit_not:s@3 @1)) (bit_not (maxmin @0 @1)))) +/* MIN (X, Y) == X -> X <= Y */ +(for minmax (min min max max) + cmp (eq ne eq ne ) + out (le gt ge lt ) + (simplify + (cmp:c (minmax:c @0 @1) @0) + (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))) + (out @0 @1)))) +/* MIN (X, 5) == 0 -> X == 0 + MIN (X, 5) == 7 -> false */ +(for cmp (eq ne) + (simplify + (cmp (min @0 INTEGER_CST@1) INTEGER_CST@2) + (if (wi::lt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0)))) + { constant_boolean_node (cmp == NE_EXPR, type); } + (if (wi::gt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0)))) + (cmp @0 @2))))) +(for cmp (eq ne) + (simplify + (cmp (max @0 INTEGER_CST@1) INTEGER_CST@2) + (if (wi::gt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0)))) + { constant_boolean_node (cmp == NE_EXPR, type); } + (if (wi::lt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0)))) + (cmp @0 @2))))) +/* MIN (X, C1) < C2 -> X < C2 || C1 < C2 */ +(for minmax (min min max max min min max max ) + cmp (lt le gt ge gt ge lt le ) + comb (bit_ior bit_ior bit_ior bit_ior bit_and bit_and bit_and bit_and) + (simplify + (cmp (minmax @0 INTEGER_CST@1) INTEGER_CST@2) + (comb (cmp @0 @2) (cmp @1 @2)))) + /* Simplifications of shift and rotates. */ (for rotate (lrotate rrotate) (simplify (rotate integer_all_onesp@0 @1) @0)) /* Optimize -1 >> x for arithmetic right shifts. */ (simplify (rshift integer_all_onesp@0 @1)