Hi! As discussed in the PR, this optimization introduced in r161707 is invalid, even when neither of the vrs include NULL, the result can still be NULL. While for usual uses (where the second argument is INTEGER_CST with all bits set except a few last ones and first argument is a pointer to real object) it is true, if one of the argument is a made up pointer (say (void *) 1), or the other argument some weird mask as in this testcase (1), we still get a NULL pointer from the operation.
Dunno if we could say use points-to info to check that one of the arguments is a real object pointer and have some limited set of pointer realignments we'd say result in non-NULL pointers. Anyway, this patch just removes the optimization, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and 9.x (the testcase is miscompiled only in 9.x)? 2019-09-03 Jakub Jelinek <ja...@redhat.com> Richard Biener <rguent...@suse.de> PR tree-optimization/91597 * tree-vrp.c (extract_range_from_binary_expr): Remove unsafe BIT_AND_EXPR optimization for pointers, even if both operand ranges don't include NULL, the result can be NULL. * gcc.c-torture/execute/pr91597.c: New test. --- gcc/tree-vrp.c.jj 2019-08-12 09:32:17.811773387 +0200 +++ gcc/tree-vrp.c 2019-09-02 19:14:14.276914085 +0200 @@ -1741,9 +1741,7 @@ extract_range_from_binary_expr (value_ra { /* For pointer types, we are really only interested in asserting whether the expression evaluates to non-NULL. */ - if (!range_includes_zero_p (&vr0) && !range_includes_zero_p (&vr1)) - vr->set_nonzero (expr_type); - else if (vr0.zero_p () || vr1.zero_p ()) + if (vr0.zero_p () || vr1.zero_p ()) vr->set_zero (expr_type); else vr->set_varying (expr_type); --- gcc/testsuite/gcc.c-torture/execute/pr91597.c.jj 2019-09-02 19:13:07.746915030 +0200 +++ gcc/testsuite/gcc.c-torture/execute/pr91597.c 2019-09-02 19:03:32.147575358 +0200 @@ -0,0 +1,48 @@ +/* PR tree-optimization/91597 */ + +enum E { A, B, C }; +struct __attribute__((aligned (4))) S { enum E e; }; + +enum E +foo (struct S *o) +{ + if (((__UINTPTR_TYPE__) (o) & 1) == 0) + return o->e; + else + return A; +} + +int +bar (struct S *o) +{ + return foo (o) == B || foo (o) == C; +} + +static inline void +baz (struct S *o, int d) +{ + if (__builtin_expect (!bar (o), 0)) + __builtin_abort (); + if (d > 2) return; + baz (o, d + 1); +} + +void +qux (struct S *o) +{ + switch (o->e) + { + case A: return; + case B: baz (o, 0); break; + case C: baz (o, 0); break; + } +} + +struct S s = { C }; + +int +main () +{ + qux (&s); + return 0; +} Jakub