The following patch is an attempt to finally fully close PR middle-end/21137.
As explained in the PR, my original patch from 2006 didn't handle the case
where there's a sign preserving NOP in the tree.  Easily fixed by calling
tree_strip_nop_conversions at the appropriate point in fold-const.c.
Most of this patch is the resulting re-indentation.

Test on x86_64-pc-linux-gnu with "make bootstrap" and "make check" with no 
regressions.

Ok for mainline? 

2016-08-05  Roger Sayle  <ro...@nextmovesoftware.com>

        PR middle-end/21137
        * fold-const.c (fold_binary_loc) <EQ_EXPR>: Allow transformations of
        ((T)(X>>C1)&C2) eq/ne 0 when the cast (T) is a sign preserving NOP by
        calling tree_strip_nop_conversions.

        * gcc.dg/fold-eqandshift-4.c: New test case.


Roger
--
Roger Sayle, Ph.D.
CEO and founder
NextMove Software Limited
Registered in England No. 07588305
Registered Office: Innovation Centre (Unit 23), Cambridge Science Park, 
Cambridge CB4 0EY

Index: fold-const.c
===================================================================
*** fold-const.c        (revision 238992)
--- fold-const.c        (working copy)
*************** fold_binary_loc (location_t loc,
*** 10604,10648 ****
         C1 is a valid shift constant, and C2 is a power of two, i.e.
         a single bit.  */
        if (TREE_CODE (arg0) == BIT_AND_EXPR
-         && TREE_CODE (TREE_OPERAND (arg0, 0)) == RSHIFT_EXPR
-         && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1))
-            == INTEGER_CST
          && integer_pow2p (TREE_OPERAND (arg0, 1))
          && integer_zerop (arg1))
        {
!         tree itype = TREE_TYPE (arg0);
!         tree arg001 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 1);
!         prec = TYPE_PRECISION (itype);
  
!         /* Check for a valid shift count.  */
!         if (wi::ltu_p (arg001, prec))
!           {
!             tree arg01 = TREE_OPERAND (arg0, 1);
!             tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
!             unsigned HOST_WIDE_INT log2 = tree_log2 (arg01);
!             /* If (C2 << C1) doesn't overflow, then ((X >> C1) & C2) != 0
!                can be rewritten as (X & (C2 << C1)) != 0.  */
!             if ((log2 + TREE_INT_CST_LOW (arg001)) < prec)
                {
!                 tem = fold_build2_loc (loc, LSHIFT_EXPR, itype, arg01, 
arg001);
!                 tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, arg000, tem);
!                 return fold_build2_loc (loc, code, type, tem,
!                                         fold_convert_loc (loc, itype, arg1));
!               }
!             /* Otherwise, for signed (arithmetic) shifts,
!                ((X >> C1) & C2) != 0 is rewritten as X < 0, and
!                ((X >> C1) & C2) == 0 is rewritten as X >= 0.  */
!             else if (!TYPE_UNSIGNED (itype))
!               return fold_build2_loc (loc, code == EQ_EXPR ? GE_EXPR : 
LT_EXPR, type,
!                                   arg000, build_int_cst (itype, 0));
!             /* Otherwise, of unsigned (logical) shifts,
!                ((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);
            }
        }
  
--- 10604,10654 ----
         C1 is a valid shift constant, and C2 is a power of two, i.e.
         a single bit.  */
        if (TREE_CODE (arg0) == BIT_AND_EXPR
          && integer_pow2p (TREE_OPERAND (arg0, 1))
          && integer_zerop (arg1))
        {
!         tree arg00 = tree_strip_nop_conversions (TREE_OPERAND (arg0, 0));
!         if (TREE_CODE (arg00) == RSHIFT_EXPR
!             && TREE_CODE (TREE_OPERAND (arg00, 1)) == INTEGER_CST)
!           {
!             tree itype = TREE_TYPE (arg0);
!             tree arg001 = TREE_OPERAND (arg00, 1);
!             prec = TYPE_PRECISION (itype);
  
!             /* Check for a valid shift count.  */
!             if (wi::ltu_p (arg001, prec))
                {
!                 tree arg01 = TREE_OPERAND (arg0, 1);
!                 tree arg000 = TREE_OPERAND (arg00, 0);
!                 unsigned HOST_WIDE_INT log2 = tree_log2 (arg01);
!                 /* If (C2 << C1) doesn't overflow, then ((X >> C1) & C2) != 0
!                   can be rewritten as (X & (C2 << C1)) != 0.  */
!                 if ((log2 + TREE_INT_CST_LOW (arg001)) < prec)
!                   {
!                     tree tem2 = fold_convert_loc (loc, itype, arg1);
!                     tem = fold_build2_loc (loc, LSHIFT_EXPR, itype,
!                                            arg01, arg001);
!                     tem = fold_build2_loc (loc, BIT_AND_EXPR, itype,
!                                            arg000, tem);
!                     return fold_build2_loc (loc, code, type, tem, tem2);
!                   }
!                 /* Otherwise, for signed (arithmetic) shifts,
!                    ((X >> C1) & C2) != 0 is rewritten as X < 0, and
!                    ((X >> C1) & C2) == 0 is rewritten as X >= 0.  */
!                 else if (!TYPE_UNSIGNED (itype))
!                   return fold_build2_loc (loc,
!                                           code == EQ_EXPR ? GE_EXPR : LT_EXPR,
!                                           type, arg000,
!                                           build_int_cst (itype, 0));
!                 /* Otherwise, of unsigned (logical) shifts,
!                    ((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);
+               }
            }
        }
  

Attachment: fold-eqandshift-4.c
Description: Binary data

Reply via email to