}
}
- /* Fold ((X >> C1) & C2) == 0 and ((X >> C1) & C2) != 0 where
- 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_OPERAND (arg0, 0);
- STRIP_NOPS (arg00);
- if (TREE_CODE (arg00) == RSHIFT_EXPR
- && TREE_CODE (TREE_OPERAND (arg00, 1)) == INTEGER_CST)
- {
- tree itype = TREE_TYPE (arg00);
- tree arg001 = TREE_OPERAND (arg00, 1);
- prec = TYPE_PRECISION (itype);
-
- /* Check for a valid shift count. */
- if (wi::ltu_p (wi::to_wide (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)
- {
- 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);
- }
- }
- }
-
/* If this is a comparison of a field, we may be able to simplify it. */
if ((TREE_CODE (arg0) == COMPONENT_REF
|| TREE_CODE (arg0) == BIT_FIELD_REF)
(cmp (bit_and:s (lshift:s @0 INTEGER_CST@1) INTEGER_CST@2) INTEGER_CST@3)
(if (tree_fits_shwi_p (@1)
&& tree_to_shwi (@1) > 0
- && tree_to_shwi (@1) < TYPE_PRECISION (TREE_TYPE (@0))
- && tree_to_shwi (@1) <= wi::ctz (wi::to_wide (@3)))
- (with { wide_int c1 = wi::to_wide (@1);
- wide_int c2 = wi::lrshift (wi::to_wide (@2), c1);
- wide_int c3 = wi::lrshift (wi::to_wide (@3), c1); }
- (cmp (bit_and @0 { wide_int_to_tree (TREE_TYPE (@0), c2); })
- { wide_int_to_tree (TREE_TYPE (@0), c3); }))))
+ && tree_to_shwi (@1) < TYPE_PRECISION (TREE_TYPE (@0)))
+ (if (tree_to_shwi (@1) > wi::ctz (wi::to_wide (@3)))
+ { constant_boolean_node (cmp == NE_EXPR, type); }
+ (with { wide_int c1 = wi::to_wide (@1);
+ wide_int c2 = wi::lrshift (wi::to_wide (@2), c1);
+ wide_int c3 = wi::lrshift (wi::to_wide (@3), c1); }
+ (cmp (bit_and @0 { wide_int_to_tree (TREE_TYPE (@0), c2); })
+ { wide_int_to_tree (TREE_TYPE (@0), c3); })))))
(simplify
(cmp (bit_and:s (rshift:s @0 INTEGER_CST@1) INTEGER_CST@2) INTEGER_CST@3)
(if (tree_fits_shwi_p (@1)
&& tree_to_shwi (@1) > 0
- && tree_to_shwi (@1) < TYPE_PRECISION (TREE_TYPE (@0))
- && tree_to_shwi (@1) <= wi::clz (wi::to_wide (@2))
- && tree_to_shwi (@1) <= wi::clz (wi::to_wide (@3)))
- (cmp (bit_and @0 (lshift @2 @1)) (lshift @3 @1)))))
+ && tree_to_shwi (@1) < TYPE_PRECISION (TREE_TYPE (@0)))
+ (with { tree t0 = TREE_TYPE (@0);
+ unsigned int prec = TYPE_PRECISION (t0);
+ wide_int c1 = wi::to_wide (@1);
+ wide_int c2 = wi::to_wide (@2);
+ wide_int c3 = wi::to_wide (@3);
+ wide_int sb = wi::set_bit_in_zero (prec - 1, prec); }
+ (if ((c2 & c3) != c3)
+ { constant_boolean_node (cmp == NE_EXPR, type); }
+ (if (TYPE_UNSIGNED (t0))
+ (if ((c3 & wi::arshift (sb, c1 - 1)) != 0)
+ { constant_boolean_node (cmp == NE_EXPR, type); }
+ (cmp (bit_and @0 { wide_int_to_tree (t0, c2 << c1); })
+ { wide_int_to_tree (t0, c3 << c1); }))
+ (with { wide_int smask = wi::arshift (sb, c1); }
+ (switch
+ (if ((c2 & smask) == 0)
+ (cmp (bit_and @0 { wide_int_to_tree (t0, c2 << c1); })
+ { wide_int_to_tree (t0, c3 << c1); }))
+ (if ((c3 & smask) == 0)
+ (cmp (bit_and @0 { wide_int_to_tree (t0, (c2 << c1) | sb); })
+ { wide_int_to_tree (t0, c3 << c1); }))
+ (if ((c2 & smask) != (c3 & smask))
+ { constant_boolean_node (cmp == NE_EXPR, type); })
+ (cmp (bit_and @0 { wide_int_to_tree (t0, (c2 << c1) | sb); })
+ { wide_int_to_tree (t0, (c3 << c1) | sb); })))))))))
/* Fold (X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
(X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1))
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int sr30eq00(char x) { return ((x >> 4) & 0x30) == 0; }
+int sr30ne00(char x) { return ((x >> 4) & 0x30) != 0; }
+int sr30eq20(char z) { return ((z >> 4) & 0x30) == 0x20; }
+int sr30ne20(char z) { return ((z >> 4) & 0x30) != 0x20; }
+int sr30eq30(char x) { return ((x >> 4) & 0x30) == 0x30; }
+int sr30ne30(char x) { return ((x >> 4) & 0x30) != 0x30; }
+int sr33eq33(char x) { return ((x >> 4) & 0x33) == 0x33; }
+int sr33ne33(char x) { return ((x >> 4) & 0x33) != 0x33; }
+
+int ur30eq00(unsigned char z) { return ((z >> 4) & 0x30) == 0; }
+int ur30ne00(unsigned char z) { return ((z >> 4) & 0x30) != 0; }
+int ur30eq30(unsigned char z) { return ((z >> 4) & 0x30) == 0x30; }
+int ur30ne30(unsigned char z) { return ((z >> 4) & 0x30) != 0x30; }
+int ur33eq03(unsigned char x) { return ((x >> 4) & 0x33) == 0x03; }
+int ur33ne03(unsigned char x) { return ((x >> 4) & 0x33) != 0x03; }
+int ur33eq30(unsigned char z) { return ((z >> 4) & 0x33) == 0x30; }
+int ur33ne30(unsigned char z) { return ((z >> 4) & 0x33) != 0x30; }
+int ur33eq33(unsigned char z) { return ((z >> 4) & 0x33) == 0x33; }
+int ur33ne33(unsigned char z) { return ((z >> 4) & 0x33) != 0x33; }
+
+int sl30eq00(char x) { return ((char)(x << 4) & 0x30) == 0; }
+int sl30ne00(char x) { return ((char)(x << 4) & 0x30) != 0; }
+int sl30eq20(char x) { return ((char)(x << 4) & 0x30) == 0x20; }
+int sl30ne20(char x) { return ((char)(x << 4) & 0x30) != 0x20; }
+int sl30eq30(char x) { return ((char)(x << 4) & 0x30) == 0x30; }
+int sl30ne30(char x) { return ((char)(x << 4) & 0x30) != 0x30; }
+int sl33eq00(char x) { return ((char)(x << 4) & 0x33) == 0; }
+int sl33ne00(char x) { return ((char)(x << 4) & 0x33) != 0; }
+int sl33eq03(char z) { return ((char)(z << 4) & 0x33) == 0x03; }
+int sl33ne03(char z) { return ((char)(z << 4) & 0x33) != 0x03; }
+int sl33eq30(char x) { return ((char)(x << 4) & 0x33) == 0x30; }
+int sl33ne30(char x) { return ((char)(x << 4) & 0x33) != 0x30; }
+int sl33eq33(char z) { return ((char)(z << 4) & 0x33) == 0x33; }
+int sl33ne33(char z) { return ((char)(z << 4) & 0x33) != 0x33; }
+
+/* { dg-final { scan-tree-dump-not " >> " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " << " "optimized" } } */
+/* { dg-final { scan-tree-dump-not "z_\[0-9\]\\(D\\)" "optimized" } } */
+/* { dg-final { scan-tree-dump-times "return \[01\]" 14 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "char z\\)" 14 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "x_\[0-9\]\\(D\\)" 18 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "char x\\)" 18 "optimized" } } */
+