Hi! It is not safe to always handle a = ~b; for bool a and b as in_p = !in_p; exp = arg0. If the current range is say +[-,-] or -[-,-] or similar (i.e. unconditional false or true), then the value of exp doesn't matter and thus the fact that exp has been negated is irrelevant.
Fixed by just making sure that the range either has 0 as high limit or 1 as low limit. In fold-const.c we actually are even more conservative and just do test for 0: case TRUTH_NOT_EXPR: /* We can only do something if the range is testing for zero. */ if (low == NULL_TREE || high == NULL_TREE || ! integer_zerop (low) || ! integer_zerop (high)) return NULL_TREE; *p_in_p = ! in_p; return arg0; Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/4.8? 2013-09-09 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/58364 * tree-ssa-reassoc.c (init_range_entry): For BIT_NOT_EXPR on BOOLEAN_TYPE, only invert in_p and continue with arg0 if the current range can't be an unconditional true or false. * gcc.c-torture/execute/pr58364.c: New test. --- gcc/tree-ssa-reassoc.c.jj 2013-08-13 12:20:45.000000000 +0200 +++ gcc/tree-ssa-reassoc.c 2013-09-09 11:30:07.416312027 +0200 @@ -1797,7 +1797,14 @@ init_range_entry (struct range_entry *r, switch (code) { case BIT_NOT_EXPR: - if (TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE) + if (TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE + /* Ensure the range is either +[-,0], +[0,0], + -[-,0], -[0,0] or +[1,-], +[1,1], -[1,-] or + -[1,1]. If it is e.g. +[-,-] or -[-,-] + or similar expression of unconditional true or + false, it should not be negated. */ + && ((high && integer_zerop (high)) + || (low && integer_onep (low)))) { in_p = !in_p; exp = arg0; --- gcc/testsuite/gcc.c-torture/execute/pr58364.c.jj 2013-09-09 11:28:59.917681919 +0200 +++ gcc/testsuite/gcc.c-torture/execute/pr58364.c 2013-09-09 11:28:40.000000000 +0200 @@ -0,0 +1,17 @@ +/* PR tree-optimization/58364 */ + +int a = 1, b, c; + +int +foo (int x) +{ + return x < 0 ? 1 : x; +} + +int +main () +{ + if (foo (a > c == (b = 0))) + __builtin_abort (); + return 0; +} Jakub