On Sun, Aug 30, 2015 at 9:57 AM, Marc Glisse <marc.gli...@inria.fr> wrote:
> Hello,
>
> just trying to shrink fold-const.c a bit more.
>
> initializer_zerop is close to what I was looking for with zerop, but I
> wasn't sure if it would be safe (it accepts some CONSTRUCTOR and
> STRING_CST). At some point I tried using sign_bit_p, but using the return of
> that function in the simplification confused the machinery too much. I added
> an "overload" of element_precision like the one in element_mode, for
> convenience.
>
> Bootstrap+testsuite on ppc64le-redhat-linux.

Ok.

Thanks,
Richard.

>
> 2015-08-31  Marc Glisse  <marc.gli...@inria.fr>
>
> gcc/
>         * tree.h (zerop): New function.
>         * tree.c (zerop): Likewise.
>         (element_precision): Handle expressions.
>         * match.pd (define_predicates): Add zerop.
>         (x <= +Inf): Fix comment.
>         (abs (x) == 0, A & C == C, A & C != 0): Converted from ...
>         * fold-const.c (fold_binary_loc): ... here. Remove.
>
> gcc/testsuite/
>         * gcc.dg/tree-ssa/cmp-1.c: New file.
>
> --
> Marc Glisse
> Index: gcc/fold-const.c
> ===================================================================
> --- gcc/fold-const.c    (revision 227316)
> +++ gcc/fold-const.c    (working copy)
> @@ -10761,25 +10761,20 @@ fold_binary_loc (location_t loc,
>                                                                         1)),
>                               arg1, 0)
>           && wi::extract_uhwi (TREE_OPERAND (arg0, 0), 0, 1) == 1)
>         {
>           return omit_two_operands_loc (loc, type,
>                                     code == NE_EXPR
>                                     ? boolean_true_node :
> boolean_false_node,
>                                     TREE_OPERAND (arg0, 1), arg1);
>         }
>
> -      /* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0.
> */
> -      if (TREE_CODE (arg0) == ABS_EXPR
> -         && (integer_zerop (arg1) || real_zerop (arg1)))
> -       return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
> arg1);
> -
>        /* If this is an EQ or NE comparison with zero and ARG0 is
>          (1 << foo) & bar, convert it to (bar >> foo) & 1.  Both require
>          two operations, but the latter can be done in one less insn
>          on machines that have only two-operand insns or on which a
>          constant cannot be the first operand.  */
>        if (TREE_CODE (arg0) == BIT_AND_EXPR
>           && integer_zerop (arg1))
>         {
>           tree arg00 = TREE_OPERAND (arg0, 0);
>           tree arg01 = TREE_OPERAND (arg0, 1);
> @@ -10868,35 +10863,20 @@ fold_binary_loc (location_t loc,
>                  ((X >> C1) & C2) != 0 is rewritten as (X,false), and
>                  ((X >> C1) & C2) == 0 is rewritten as (X,true).  */
>               else
>                 return omit_one_operand_loc (loc, type,
>                                          code == EQ_EXPR ? integer_one_node
>                                                          :
> integer_zero_node,
>                                          arg000);
>             }
>         }
>
> -      /* If we have (A & C) == C where C is a power of 2, convert this into
> -        (A & C) != 0.  Similarly for NE_EXPR.  */
> -      if (TREE_CODE (arg0) == BIT_AND_EXPR
> -         && integer_pow2p (TREE_OPERAND (arg0, 1))
> -         && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
> -       return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR,
> type,
> -                           arg0, fold_convert_loc (loc, TREE_TYPE (arg0),
> -                                                   integer_zero_node));
> -
> -      /* If we have (A & C) != 0 or (A & C) == 0 and C is the sign
> -        bit, then fold the expression into A < 0 or A >= 0.  */
> -      tem = fold_single_bit_test_into_sign_test (loc, code, arg0, arg1,
> type);
> -      if (tem)
> -       return tem;
> -
>        /* If we have (A & C) == D where D & ~C != 0, convert this into 0.
>          Similarly for NE_EXPR.  */
>        if (TREE_CODE (arg0) == BIT_AND_EXPR
>           && TREE_CODE (arg1) == INTEGER_CST
>           && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
>         {
>           tree notc = fold_build1_loc (loc, BIT_NOT_EXPR,
>                                    TREE_TYPE (TREE_OPERAND (arg0, 1)),
>                                    TREE_OPERAND (arg0, 1));
>           tree dandnotc
> Index: gcc/match.pd
> ===================================================================
> --- gcc/match.pd        (revision 227316)
> +++ gcc/match.pd        (working copy)
> @@ -21,20 +21,21 @@ for more details.
>  You should have received a copy of the GNU General Public License
>  along with GCC; see the file COPYING3.  If not see
>  <http://www.gnu.org/licenses/>.  */
>
>
>  /* Generic tree predicates we inherit.  */
>  (define_predicates
>     integer_onep integer_zerop integer_all_onesp integer_minus_onep
>     integer_each_onep integer_truep integer_nonzerop
>     real_zerop real_onep real_minus_onep
> +   zerop
>     CONSTANT_CLASS_P
>     tree_expr_nonnegative_p
>     integer_pow2p
>     HONOR_NANS)
>
>  /* Operator lists.  */
>  (define_operator_list tcc_comparison
>    lt   le   eq ne ge   gt   unordered ordered   unlt unle ungt unge uneq
> ltgt)
>  (define_operator_list inverted_tcc_comparison
>    ge   gt   ne eq lt   le   ordered   unordered ge   gt   le   lt   ltgt
> uneq)
> @@ -1570,21 +1571,21 @@ along with GCC; see the file COPYING3.
>       }
>       (switch
>        /* x > +Inf is always false, if with ignore sNANs.  */
>        (if (code == GT_EXPR
>            && ! HONOR_SNANS (@0))
>         { constant_boolean_node (false, type); })
>        (if (code == LE_EXPR)
>         /* x <= +Inf is always true, if we don't case about NaNs.  */
>         (if (! HONOR_NANS (@0))
>         { constant_boolean_node (true, type); }
> -       /* x <= +Inf is the same as x == x, i.e. isfinite(x).  */
> +       /* x <= +Inf is the same as x == x, i.e. !isnan(x).  */
>         (eq @0 @0)))
>        /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX.  */
>        (if (code == EQ_EXPR || code == GE_EXPR)
>         (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
>         (if (neg)
>          (lt @0 { build_real (TREE_TYPE (@0), max); })
>          (gt @0 { build_real (TREE_TYPE (@0), max); }))))
>        /* x < +Inf is always equal to x <= DBL_MAX.  */
>        (if (code == LT_EXPR)
>         (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); }
> @@ -1727,20 +1728,26 @@ along with GCC; see the file COPYING3.
>     (scmp @0 @1)))
>   (simplify
>    (cmp (negate @0) CONSTANT_CLASS_P@1)
>    (if (FLOAT_TYPE_P (TREE_TYPE (@0))
>         || (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
>            && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))))
>     (with { tree tem = fold_unary (NEGATE_EXPR, TREE_TYPE (@0), @1); }
>      (if (tem && !TREE_OVERFLOW (tem))
>       (scmp @0 { tem; }))))))
>
> +/* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0.  */
> +(for op (eq ne)
> + (simplify
> +  (op (abs @0) zerop@1)
> +  (op @0 @1)))
> +
>  /* From fold_sign_changed_comparison and fold_widened_comparison.  */
>  (for cmp (simple_comparison)
>   (simplify
>    (cmp (convert@0 @00) (convert?@1 @10))
>    (if (TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE
>         /* Disable this optimization if we're casting a function pointer
>           type on targets that require function pointer canonicalization.
> */
>         && !(targetm.have_canonicalize_funcptr_for_compare ()
>             && TREE_CODE (TREE_TYPE (@00)) == POINTER_TYPE
>             && TREE_CODE (TREE_TYPE (TREE_TYPE (@00))) == FUNCTION_TYPE)
> @@ -1833,20 +1840,42 @@ along with GCC; see the file COPYING3.
>   (simplify
>    (cmp (convert?@3 (bit_xor @0 INTEGER_CST@1)) INTEGER_CST@2)
>    (if (tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@0)))
>     (cmp @0 (bit_xor @1 (convert @2)))))
>
>   (simplify
>    (cmp (convert? addr@0) integer_zerop)
>    (if (tree_single_nonzero_warnv_p (@0, NULL))
>     { constant_boolean_node (cmp == NE_EXPR, type); })))
>
> +/* If we have (A & C) == C where C is a power of 2, convert this into
> +   (A & C) != 0.  Similarly for NE_EXPR.  */
> +(for cmp (eq ne)
> +     icmp (ne eq)
> + (simplify
> +  (cmp (bit_and@2 @0 integer_pow2p@1) @1)
> +  (icmp @2 { build_zero_cst (TREE_TYPE (@0)); })))
> +
> +/* If we have (A & C) != 0 where C is the sign bit of A, convert
> +   this into A < 0.  Similarly for (A & C) == 0 into A >= 0.  */
> +(for cmp (eq ne)
> +     ncmp (ge lt)
> + (simplify
> +  (cmp (bit_and (convert?@2 @0) integer_pow2p@1) integer_zerop)
> +  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
> +       && (TYPE_PRECISION (TREE_TYPE (@0))
> +          == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@0))))
> +       && element_precision (@2) >= element_precision (@0)
> +       && wi::only_sign_bit_p (@1, element_precision (@0)))
> +   (with { tree stype = signed_type_for (TREE_TYPE (@0)); }
> +    (ncmp (convert:stype @0) { build_zero_cst (stype); })))))
> +
>  /* When the addresses are not directly of decls compare base and offset.
>     This implements some remaining parts of fold_comparison address
>     comparisons but still no complete part of it.  Still it is good
>     enough to make fold_stmt not regress when not dispatching to
> fold_binary.  */
>  (for cmp (simple_comparison)
>   (simplify
>    (cmp (convert1?@2 addr@0) (convert2? addr@1))
>    (with
>     {
>       HOST_WIDE_INT off0, off1;
> Index: gcc/testsuite/gcc.dg/tree-ssa/cmp-1.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/tree-ssa/cmp-1.c       (revision 0)
> +++ gcc/testsuite/gcc.dg/tree-ssa/cmp-1.c       (working copy)
> @@ -0,0 +1,19 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O -fdump-tree-gimple -fdump-tree-optimized" } */
> +
> +int f(int a){
> +  int b = -__INT_MAX__-1;
> +  a &= b;
> +  return a == b;
> +}
> +int g(int x){
> +    x = x < 0 ? -x : x;
> +    return x == 0;
> +}
> +
> +/* This should work even if int is not 32 bits, it is just not meaningful
> in
> +   that case.  */
> +/* { dg-final { scan-tree-dump-not "-2147483648" "optimized"} } */
> +/* { dg-final { scan-tree-dump " < 0" "optimized"} } */
> +/* { dg-final { scan-tree-dump "ABS_EXPR" "gimple"} } */
> +/* { dg-final { scan-tree-dump-not "ABS_EXPR" "optimized"} } */
> Index: gcc/tree.c
> ===================================================================
> --- gcc/tree.c  (revision 227316)
> +++ gcc/tree.c  (working copy)
> @@ -2208,20 +2208,31 @@ grow_tree_vec_stat (tree v, int len MEM_
>
>    record_node_allocation_statistics (TREE_VEC, length - oldlength);
>
>    v = (tree) ggc_realloc (v, length PASS_MEM_STAT);
>
>    TREE_VEC_LENGTH (v) = len;
>
>    return v;
>  }
>
> +/* Return 1 if EXPR is the constant zero, whether it is integral, float or
> +   fixed, and scalar, complex or vector.  */
> +
> +int
> +zerop (const_tree expr)
> +{
> +  return (integer_zerop (expr)
> +         || real_zerop (expr)
> +         || fixed_zerop (expr));
> +}
> +
>  /* Return 1 if EXPR is the integer constant zero or a complex constant
>     of zero.  */
>
>  int
>  integer_zerop (const_tree expr)
>  {
>    STRIP_NOPS (expr);
>
>    switch (TREE_CODE (expr))
>      {
> @@ -7505,20 +7516,22 @@ valid_constant_size_p (const_tree size)
>      return false;
>    return true;
>  }
>
>  /* Return the precision of the type, or for a complex or vector type the
>     precision of the type of its elements.  */
>
>  unsigned int
>  element_precision (const_tree type)
>  {
> +  if (!TYPE_P (type))
> +    type = TREE_TYPE (type);
>    enum tree_code code = TREE_CODE (type);
>    if (code == COMPLEX_TYPE || code == VECTOR_TYPE)
>      type = TREE_TYPE (type);
>
>    return TYPE_PRECISION (type);
>  }
>
>  /* Return true if CODE represents an associative tree code.  Otherwise
>     return false.  */
>  bool
> Index: gcc/tree.h
> ===================================================================
> --- gcc/tree.h  (revision 227316)
> +++ gcc/tree.h  (working copy)
> @@ -4102,20 +4102,24 @@ extern bool initializer_zerop (const_tre
>
>  /* Given a vector VEC, return its first element if all elements are
>     the same.  Otherwise return NULL_TREE.  */
>
>  extern tree uniform_vector_p (const_tree);
>
>  /* Given a CONSTRUCTOR CTOR, return the element values as a vector.  */
>
>  extern vec<tree, va_gc> *ctor_to_vec (tree);
>
> +/* zerop (tree x) is nonzero if X is a constant of value 0.  */
> +
> +extern int zerop (const_tree);
> +
>  /* integer_zerop (tree x) is nonzero if X is an integer constant of value
> 0.  */
>
>  extern int integer_zerop (const_tree);
>
>  /* integer_onep (tree x) is nonzero if X is an integer constant of value 1.
> */
>
>  extern int integer_onep (const_tree);
>
>  /* integer_onep (tree x) is nonzero if X is an integer constant of value 1,
> or
>     a vector or complex where each part is 1.  */
>

Reply via email to