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); + } } }
fold-eqandshift-4.c
Description: Binary data