This adds BIT_XOR_EXPR support to propagation, similar to how we have BIT_IOR_EXPR and BIT_AND_EXPR support (but without the adjustment for constant vr0/1 min/max which I think we cannot do for XOR).
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2011-08-05 Richard Guenther <rguent...@suse.de> PR tree-optimization/49984 * tree-vrp.c (extract_range_from_binary_expr_1): Handle BIT_XOR_EXPR. * gcc.dg/tree-ssa/vrp59.c: New testcase. Index: gcc/tree-vrp.c =================================================================== *** gcc/tree-vrp.c (revision 177423) --- gcc/tree-vrp.c (working copy) *************** extract_range_from_binary_expr_1 (value_ *** 2214,2220 **** && code != MIN_EXPR && code != MAX_EXPR && code != BIT_AND_EXPR ! && code != BIT_IOR_EXPR) { set_value_range_to_varying (vr); return; --- 2214,2221 ---- && code != MIN_EXPR && code != MAX_EXPR && code != BIT_AND_EXPR ! && code != BIT_IOR_EXPR ! && code != BIT_XOR_EXPR) { set_value_range_to_varying (vr); return; *************** extract_range_from_binary_expr_1 (value_ *** 2635,2641 **** min = vrp_int_const_binop (code, vr0.min, vr1.max); max = vrp_int_const_binop (code, vr0.max, vr1.min); } ! else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR) { bool int_cst_range0, int_cst_range1; double_int may_be_nonzero0, may_be_nonzero1; --- 2636,2642 ---- min = vrp_int_const_binop (code, vr0.min, vr1.max); max = vrp_int_const_binop (code, vr0.max, vr1.min); } ! else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR) { bool int_cst_range0, int_cst_range1; double_int may_be_nonzero0, may_be_nonzero1; *************** extract_range_from_binary_expr_1 (value_ *** 2694,2699 **** --- 2695,2729 ---- if (int_cst_range1) min = vrp_int_const_binop (MAX_EXPR, min, vr1.min); } + else if (code == BIT_XOR_EXPR) + { + double_int result_zero_bits, result_one_bits; + result_zero_bits + = double_int_ior (double_int_and (must_be_nonzero0, + must_be_nonzero1), + double_int_not + (double_int_ior (may_be_nonzero0, + may_be_nonzero1))); + result_one_bits + = double_int_ior (double_int_and + (must_be_nonzero0, + double_int_not (may_be_nonzero1)), + double_int_and + (must_be_nonzero1, + double_int_not (may_be_nonzero0))); + max = double_int_to_tree (expr_type, + double_int_not (result_zero_bits)); + min = double_int_to_tree (expr_type, result_one_bits); + /* Return a [min, max] range if we know the + result range is either positive or negative. */ + if (tree_int_cst_sgn (max) >= 0) + /* The range is bound by a lower value of 0. */; + else if (tree_int_cst_sgn (min) < 0) + /* The range is bound by an upper value of -1. */; + else + /* We don't know whether the sign bit is set or not. */ + max = min = NULL_TREE; + } else { set_value_range_to_varying (vr); Index: gcc/testsuite/gcc.dg/tree-ssa/vrp59.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/vrp59.c (revision 0) --- gcc/testsuite/gcc.dg/tree-ssa/vrp59.c (revision 0) *************** *** 0 **** --- 1,35 ---- + /* { dg-do compile } */ + /* { dg-options "-O2 -fno-tree-ccp -fdump-tree-vrp1" } */ + + int f(int x) + { + if (x >= 0 && x <= 3) + { + x = x ^ 3; + x = x & 3; + } + return x; + } + + int g(int x) + { + if (x >= 0 && x <= 3) + { + x = x ^ 2; + x = x & 3; + } + return x; + } + + int h(int x) + { + if (x >= 0 && x <= 3) + { + x = x ^ 1; + x = x & 3; + } + return x; + } + + /* { dg-final { scan-tree-dump-not " & 3;" "vrp1" } } */ + /* { dg-final { cleanup-tree-dump "vrp1" } } */